moved stuff out of app since it is used for routing

This commit is contained in:
2024-11-20 23:16:26 -05:00
parent d1bd68e720
commit fd08fd2886
136 changed files with 56 additions and 46 deletions

View File

@@ -1,29 +0,0 @@
import { sectionLinks } from "@/app/lib/linkList/sectionLinks";
import Link from "next/link";
import armoryLinks from "@/app/lib/linkList/sectionLinks";
let linksArray = [
sectionLinks.UPPERS,
sectionLinks.LOWERS,
sectionLinks.BARRELS,
sectionLinks.OPTICS,
sectionLinks.ACCESSORIES,
];
export const Armory = (props) => {
return (
(<div>
{armoryLinks.length}
<h4>{props.titleText}</h4>
<ul>
{linksArray.map((link, index) => (
<li key={index}>
<Link href={link.URL}>
{link.TEXT}
</Link>
</li>
))}
</ul>
</div>)
);
}
export default Armory;

View File

@@ -1,23 +0,0 @@
{
"name": "armory",
"version": "0.0.0",
"private": true,
"main": "./index",
"author": {
"name": "Sean Strawsburg",
"email": "sean@goforward.group",
"url": "https://goforward.group/"
},
"contributors": [
{
"name": "Don Strawsburg",
"email": "don@goforward.group",
"url": "https://goforward.group/"
},
{
"name": "Sean Strawsburg",
"email": "sean@goforward.group",
"url": "https://goforward.group/"
}
]
}

View File

@@ -1 +0,0 @@
@import '../../scss/variables.scss';

View File

@@ -1,38 +0,0 @@
import React from 'react';
import styles from './style.module.scss'
const Button = ({
children,
className,
color = 'black',
type = 'button',
...props
}) => (
<button
className={`${className} Button Button_${color}`}
type={type}
{...props}
>
{children}
</button>
);
const ButtonUnobtrusive = ({
children,
className,
type = 'button',
...props
}) => (
<button
className={`${className} Button_unobtrusive`}
type={type}
{...props}
>
{children}
</button>
);
export { ButtonUnobtrusive };
export default Button;

View File

@@ -1,23 +0,0 @@
{
"name": "button",
"version": "0.0.0",
"private": true,
"main": "./index",
"author": {
"name": "Sean Strawsburg",
"email": "sean@goforward.group",
"url": "https://goforward.group/"
},
"contributors": [
{
"name": "Don Strawsburg",
"email": "don@goforward.group",
"url": "https://goforward.group/"
},
{
"name": "Sean Strawsburg",
"email": "sean@goforward.group",
"url": "https://goforward.group/"
}
]
}

View File

@@ -1,46 +0,0 @@
.Button {
padding: 10px;
background: none;
cursor: pointer;
transition: color 0.25s ease-in-out;
transition: background 0.25s ease-in-out;
}
.Button_white {
border: 1px solid #fff;
color: #fff;
}
.Button_white:hover {
color: #000;
background: #fff;
}
.Button_black {
border: 1px solid #000;
color: #000;
}
.Button_black:hover {
color: #fff;
background: #000;
}
.Button_unobtrusive {
padding: 0;
color: #000;
background: none;
border: none;
cursor: pointer;
opacity: 1;
transition: opacity 0.25s ease-in-out;
outline: none;
}
.Button_unobtrusive:hover {
opacity: 0.35;
}
.Button_unobtrusive:focus {
outline: none;
}

View File

@@ -1,8 +0,0 @@
const DSTPageHeader = props => {
return (
<div>{props.title}</div>
)
}
export default DSTPageHeader

View File

@@ -1,23 +0,0 @@
{
"name": "DSTPageHeader",
"version": "0.0.0",
"private": true,
"main": "./index",
"author": {
"name": "Don Strawsburg",
"email": "don@goforward.group",
"url": "https://goforward.group/"
},
"contributors": [
{
"name": "Don Strawsburg",
"email": "don@goforward.group",
"url": "https://goforward.group/"
},
{
"name": "Sean Strawsburg",
"email": "sean@goforward.group",
"url": "https://goforward.group/"
}
]
}

View File

@@ -1,11 +0,0 @@
import React from 'react';
import styles from './style.module.css';
const ErrorMessage = ({ error }) => (
<div className="ErrorMessage">
<small>{error.toString()}</small>
</div>
);
export default ErrorMessage;

View File

@@ -1,23 +0,0 @@
{
"name": "error",
"version": "0.0.0",
"private": true,
"main": "./index",
"author": {
"name": "Sean Strawsburg",
"email": "sean@goforward.group",
"url": "https://goforward.group/"
},
"contributors": [
{
"name": "Don Strawsburg",
"email": "don@goforward.group",
"url": "https://goforward.group/"
},
{
"name": "Sean Strawsburg",
"email": "sean@goforward.group",
"url": "https://goforward.group/"
}
]
}

View File

@@ -1,5 +0,0 @@
.ErrorMessage {
margin: 20px;
display: flex;
justify-content: center;
}

View File

@@ -1,13 +0,0 @@
import { ListItemText, Link } from "@mui/material";
import styles from './styles.module.css'
import { withStyles } from '@mui/material/styles';
import styled from '@emotion/styled'
import React from "react";
export default function FooterLink(props) {
return (
<ListItemText inset >
<Link href={props.href}><a className={styles.navLinks}>{props.title}</a></Link>
</ListItemText>
)
}

View File

@@ -1,23 +0,0 @@
{
"name": "footerlink",
"version": "0.0.0",
"private": true,
"main": "./index",
"author": {
"name": "Sean Strawsburg",
"email": "sean@goforward.group",
"url": "https://goforward.group/"
},
"contributors": [
{
"name": "Don Strawsburg",
"email": "don@goforward.group",
"url": "https://goforward.group/"
},
{
"name": "Sean Strawsburg",
"email": "sean@goforward.group",
"url": "https://goforward.group/"
}
]
}

View File

@@ -1,5 +0,0 @@
.navLinks:hover {
font-weight: bold;
text-decoration : none;
}

View File

@@ -1,27 +0,0 @@
import { sectionLinks } from "@/app/lib/linkList/sectionLinks";
import Link from "next/link";
let linksArray = [
sectionLinks.BLOG,
sectionLinks.PRICEDROPS,
sectionLinks.BUILDS,
sectionLinks.BUILDGUIDES,
];
export const GroundZero = (props) => {
return (
(<div>
<h4>{props.titleText}</h4>
<ul>
{linksArray.map((link, index) => (
<li key={index}>
<Link href={link.URL}>
{link.TEXT}
</Link>
</li>
))}
</ul>
</div>)
);
}
export default GroundZero;

View File

@@ -1,23 +0,0 @@
{
"name": "groundzero",
"version": "0.0.0",
"private": true,
"main": "./index",
"author": {
"name": "Sean Strawsburg",
"email": "sean@goforward.group",
"url": "https://goforward.group/"
},
"contributors": [
{
"name": "Don Strawsburg",
"email": "don@goforward.group",
"url": "https://goforward.group/"
},
{
"name": "Sean Strawsburg",
"email": "sean@goforward.group",
"url": "https://goforward.group/"
}
]
}

View File

@@ -1 +0,0 @@
@import '../../scss/variables.scss';

View File

@@ -1,27 +0,0 @@
import { infoLinks } from "@/app/lib/linkList/infoLinks";
import Link from "next/link";
let linksArray = [
infoLinks.ABOUT,
infoLinks.FAQ,
infoLinks.DISCLOSURE,
infoLinks.PRIVACYPOLICY,
infoLinks.PIP,
infoLinks.TOS
];
export const Information = (props) => {
return (
(<div>
<h4>{props.titleText}</h4>
<ul>
{linksArray.map((link, index) => (
<li key={index}>
<Link href={link.URL}>
{link.TEXT}
</Link>
</li>
))}
</ul>
</div>)
);
}
export default Information;

View File

@@ -1,23 +0,0 @@
{
"name": "information",
"version": "0.0.0",
"private": true,
"main": "./index",
"author": {
"name": "Sean Strawsburg",
"email": "sean@goforward.group",
"url": "https://goforward.group/"
},
"contributors": [
{
"name": "Don Strawsburg",
"email": "don@goforward.group",
"url": "https://goforward.group/"
},
{
"name": "Sean Strawsburg",
"email": "sean@goforward.group",
"url": "https://goforward.group/"
}
]
}

View File

@@ -1 +0,0 @@
@import '../../scss/variables.scss';

View File

@@ -1,70 +0,0 @@
import React from 'react';
import { makeStyles } from '@mui/material/styles';
import InputLabel from '@mui/material/InputLabel';
import FormHelperText from '@mui/material/FormHelperText';
import FormControl from '@mui/material/FormControl';
import Select from '@mui/material/Select';
import NativeSelect from '@mui/material/NativeSelect';
import { useQuery, gql } from "@apollo/client";
const useStyles = makeStyles((theme) => ({
formControl: {
margin: theme.spacing(1),
minWidth: 120,
},
selectEmpty: {
marginTop: theme.spacing(2),
},
}));
const GET_STATES = gql`
{
states {
abbrev
name
}
}`
export default function StateNativeSelects() {
const classes = useStyles();
const [state, setState] = React.useState({
abbrev: '',
name: '',
});
const handleChange = (event) => {
const name = event.target.name;
setState({
...state,
[name]: event.target.value,
});
};
const { loading, error, data } = useQuery(GET_STATES);
if (loading) return <p>Loading...</p>;
if (error) return <p>Error :(</p>;
return (
<div>
<FormControl className={classes.formControl}>
<InputLabel htmlFor="state-native-simple">State</InputLabel>
<Select
native
value={state.abbrev}
onChange={handleChange}
inputProps={{
name: 'abbrev',
id: 'abbrev-native-simple',
}}
>
<option aria-label="None" value="" />
{data.states.map(({ abbrev, name }) => (
<option value={abbrev}>{name}</option>
))}
</Select>
</FormControl>
</div>
);
}

View File

@@ -1,20 +0,0 @@
import Link from "next/link";
export default function About() {
return (
(
<section id="about" className="bg-gray-200 py-20">
<div className="container mx-auto px-6 text-center">
<h3 className="text-3xl font-bold mb-6">About Us</h3>
<p className="text-gray-700">
Ballistic Builderis your go-to platform for customizing, building,
and exploring firearm parts. Designed for enthusiasts by
enthusiasts, we make firearm building easy and accessible.
</p>
</div>
</section>
)
)
}

View File

@@ -1,10 +0,0 @@
import Link from "next/link";
export default function BB_Base_Component() {
return (
(
<div />
)
)
}

View File

@@ -1,24 +0,0 @@
import Link from "next/link";
export default function Contact() {
return (
(
<section id="contact" className="py-20">
<div className="container mx-auto px-6 text-center">
<h3 className="text-3xl font-bold mb-6">Contact Us</h3>
<p className="text-gray-700 mb-6">
Have questions or feedback? Wed love to hear from you!
</p>
<Link
href="mailto:support@firearmbuilder.com"
className="bg-blue-500 hover:bg-blue-700 text-white font-bold py-2 px-4 rounded">
Email Us
</Link>
</div>
</section>
)
)
}

View File

@@ -1,34 +0,0 @@
import Link from "next/link";
export default function FeaturesSection() {
return (
(
<section id="features" className="py-20">
<div className="container mx-auto px-6 text-center">
<h3 className="text-3xl font-bold mb-6">Features</h3>
<div className="grid grid-cols-1 md:grid-cols-3 gap-8">
<div className="bg-white shadow-md p-6 rounded">
<h4 className="text-xl font-bold mb-2">Extensive Database</h4>
<p className="text-gray-600">
Access thousands of firearm parts from trusted resellers.
</p>
</div>
<div className="bg-white shadow-md p-6 rounded">
<h4 className="text-xl font-bold mb-2">Compatibility Checker</h4>
<p className="text-gray-600">
Ensure every part works perfectly together.
</p>
</div>
<div className="bg-white shadow-md p-6 rounded">
<h4 className="text-xl font-bold mb-2">Save & Share Builds</h4>
<p className="text-gray-600">
Save your builds or share them with friends.
</p>
</div>
</div>
</div>
</section>
)
)
}

View File

@@ -1,14 +0,0 @@
import Link from "next/link";
export default function Footer() {
return (
(
<footer className="bg-gray-800 text-white py-4">
<div className="container mx-auto px-6 text-center">
<p>&copy; {new Date().getFullYear()} Firearm Builder. All rights reserved.</p>
</div>
</footer>
)
)
}

View File

@@ -1,74 +0,0 @@
import React, { Component } from 'react'
import PropTypes from 'prop-types' //ES6
import styles from './styles.module.css'
import List from '@mui/material/List'
import ListItem from '@mui/material/ListItem';
import ListItemText from '@mui/material/ListItemText';
import TypoGraphy from '@mui/material/Typography'
import Link from 'next/link'
import { makeStyles } from '@mui/material/styles';
const useStyles = makeStyles((theme) => ({
root: {
width: '75%',
maxWidth: 260,
/* backgroundColor: theme.palette.background.paper, */
float : 'right',
marginRight:'2%',
fontSize : '.80em'
},
}));
export default function FooterLinks() {
const classes = useStyles();
return (
(<div className={classes.root}>
<TypoGraphy variant="subtitle1" color="inherit" >
<List component="nav" >
<ListItemText inset >
<TypoGraphy color="inherit" variant="subtitle2">
<Link href="/info/faq" className={styles.navLinks}>FAQ</Link>
</TypoGraphy>
</ListItemText>
<ListItemText inset >
<TypoGraphy color="inherit" variant="subtitle2">
<Link href="/info/tos" className={styles.navLinks}>Terms Of Service</Link>
</TypoGraphy>
</ListItemText>
<ListItemText inset>
<TypoGraphy color="inherit" variant="subtitle2">
<Link href="/info/contactus" className={styles.navLinks}>Contact Us</Link>
</TypoGraphy>
</ListItemText>
<ListItemText inset>
<TypoGraphy color="inherit" variant="subtitle2">
<Link href="/info/privacypolicy" className={styles.navLinks}>Privacy Policy</Link>
</TypoGraphy>
</ListItemText>
<ListItemText inset>
<TypoGraphy color="inherit" variant="subtitle2">
<Link href="/info/pip" className={styles.navLinks}>Personal Information Policy</Link>
</TypoGraphy>
</ListItemText>
<ListItemText inset>
<TypoGraphy color="inherit" variant="subtitle2">
<Link href="/info/disclosure" className={styles.navLinks}>Disclosure</Link>
</TypoGraphy>
</ListItemText>
</List>
</TypoGraphy>
</div>)
);
}

View File

@@ -1,53 +0,0 @@
import React, { Component } from 'react'
import PropTypes from 'prop-types' //ES6
import styles from './styles.module.css'
import List from '@mui/material/List'
import ListItem from '@mui/material/ListItem';
import ListItemText from '@mui/material/ListItemText';
import TypoGraphy from '@mui/material/Typography'
import Link from 'next/link'
import { withStyles } from '@mui/material/styles';
import styled from '@emotion/styled'
import FooterLink from '@/src/app/Fragments/FooterLink';
class FooterLinks extends React.Component {
constructor(props) {
super(props)
this.state = {
}
}
render() {
const { classes } = this.props;
return (
<FooterLinksStyled>
<div className="footer-links">
<List component="nav" >
<React.Fragment>
<FooterLink href="/info/faq" title="FAQ" />
<FooterLink href="/info/tos" title="Terms Of Service" />
<FooterLink href="/info/contactus" title="Contact Us" />
<FooterLink href="/info/privacypolicy" title="Privacy Policy" />
<FooterLink href="/info/pip" title="Personal Information Policy" />
<FooterLink href="/info/disclosure" title="Disclosure" />
<FooterLink href="/info/about" title="About Us" />
</React.Fragment>
</List>
</div>
</FooterLinksStyled>
)
}
}
const FooterLinksStyled = styled.div`
.footer-links nav {
display: flex;
flex-direction: row;
justify-content: space-around;
width: 100%;
}
`
// export default withStyles(useStyles)(FooterLinks);
export default FooterLinks;

View File

@@ -1,23 +0,0 @@
{
"name": "footerlinks",
"version": "0.0.0",
"private": true,
"main": "./index",
"author": {
"name": "Don Strawsburg",
"email": "don@goforward.group",
"url": "https://goforward.group/"
},
"contributors": [
{
"name": "Don Strawsburg",
"email": "don@goforward.group",
"url": "https://goforward.group/"
},
{
"name": "Sean Strawsburg",
"email": "sean@goforward.group",
"url": "https://goforward.group/"
}
]
}

View File

@@ -1,7 +0,0 @@
.navLinks {
color:#000;
}
.navLinks:hover {
font-weight: bold;
text-decoration : none;
}

View File

@@ -1,43 +0,0 @@
import React, { Component } from "react";
import PropTypes from "prop-types";
import styles from './styles.module.scss';
import Copyright from "@/src/app/components/GB_Info/Copyright";
import FooterLinks from "./FooterLinks";
import Link from "next/link";
import { infoLinks } from "@/src/app/lib/linkList/infoLinks";
import { sectionLinks } from "@/src//app/lib/linkList/sectionLinks";
import Armory from '@/src/app/Fragments/Armory';
import GroundZero from "@/src/app/Fragments/GroundZero";
import Information from "@/src/app/Fragments/Information";
export const Footer = () => {
return (
// <div className={styles.Footer}>
// <FooterLinks></FooterLinks>
// <Copyright></Copyright>
// </div>
(<>
<footer className={styles.footer}>
<nav className={styles.linksContainer}>
<div className={styles.brand}>
<div className={styles.logo}>
<span>Logo</span>
</div>
<p>Find Parts.</p>
<p>Build Guns.</p>
<p>Freedom On.</p>
</div>
<Armory titleText="Armory"/>
<GroundZero titleText="Ground Zero"/>
<Information titleText="Information"/>
</nav>
</footer>
<Copyright></Copyright>
</>)
);
}
Footer.propTypes = {};
export default Footer;

View File

@@ -1,23 +0,0 @@
{
"name": "footer",
"version": "0.0.0",
"private": true,
"main": "./index",
"author": {
"name": "Don Strawsburg",
"email": "don@goforward.group",
"url": "https://goforward.group/"
},
"contributors": [
{
"name": "Don Strawsburg",
"email": "don@goforward.group",
"url": "https://goforward.group/"
},
{
"name": "Sean Strawsburg",
"email": "sean@goforward.group",
"url": "https://goforward.group/"
}
]
}

View File

@@ -1,59 +0,0 @@
@import '../../scss/variables.scss';
.footer {
background: #4c5c3f;
min-height: 300px;
height: 100%;
padding: 1rem 0;
border-top: 2px solid #000;
.brand {
font-weight: bolder;
text-transform: uppercase;
letter-spacing: 1px;
font-size: 1.25em;
color:#FFF;
.logo span {
display: inline-block;
height: 100px;
width: 100px;
background: #FFF;
color:#4c5c3f;
text-align: center;
}
}
}
.linksContainer {
display: flex;
justify-content: space-around;
align-items: flex-start;
ul {
display: flex;
flex-direction: column;
list-style: none;
padding: 0;
li {
color:#FFF;
a {
color: #fff;
transition: all 500ms ease;
&:hover {
color: #ADA17B;
font-weight: bold;
}
}
}
}
h4 {
color: #FFF;
border-bottom: 2px solid #fff;
margin-bottom: 10px;
}
}

View File

@@ -1,106 +0,0 @@
import React, { Component } from 'react';
import PropTypes from 'prop-types'; //ES6
import styles from './styles.module.css';
import Link from 'next/link';
import AppBar from '@mui/material/AppBar';
import Toolbar from '@mui/material/Toolbar';
import List from '@mui/material/List';
import ListItem from '@mui/material/ListItem';
import ListItemText from '@mui/material//ListItemText';
// import TypoGraphy from '@mui/material/Typography';
import Button from '@mui/material//Button';
import { infoLinks } from '@/app/lib/linkList/infoLinks';
import sectionLinks from '@/app/lib/linkList/sectionLinks';
export default class Header extends Component {
constructor(props) {
super(props)
this.state = {
}
}
render() {
return (
(<div>
<div className="topheader">
<Link href="/" legacyBehavior><a className="logo">Gun Builder</a>
</Link>
</div>
<AppBar position="static">
<Toolbar>
<List component="nav">
<ListItem component="div" className="nav-item">
<ListItemText inset>
<Link href={sectionLinks.UPPERS.URL} legacyBehavior><a className={styles.navLinks}>{sectionLinks.UPPERS.TEXT}</a></Link>
</ListItemText>
<ListItemText inset>
<Link href={sectionLinks.PARTSLIST.URL} legacyBehavior><a className={styles.navLinks}>{sectionLinks.PARTSLIST.TEXT}</a></Link>
</ListItemText>
<ListItemText inset>
<Link href={sectionLinks.BUILDS.URL} legacyBehavior><a className={styles.navLinks}>{sectionLinks.BUILDS.TEXT}</a></Link>
</ListItemText>
<ListItemText inset>
<Link href={sectionLinks.BLOG.URL} legacyBehavior><a className={styles.navLinks}>{sectionLinks.BLOG.TEXT}</a></Link>
</ListItemText>
{/* <ListItemText inset>
<Link href="/admin"><a className={styles.navLinks}>Admin</a></Link>
</ListItemText> */}
</ListItem>
</List>
</Toolbar>
</AppBar>
<style jsx>{`
header {
background:#101010;
color:#fff;
}
.topheader {
background:#111;
height: 4em;
color: #000;
display: flex;
justify-content: center;
flex-direction: column;
}
.topheader a {
color:#fff;
padding-left: 15px;
text-transform: uppercase;
font-weight: bold;
letter-spacing: 2px;
}
.nav {
display: flex;
background: #4c5d34;
}
ul {
list-style: none;
padding: 0;
display: flex;
margin: 0;
height: 100%;
}
ul li {
margin-right: 10px;
padding:1em 1.5em;
border-right:2px solid rgba(0,0,0,.3);
text-transform: uppercase;
font-weight:bold;
letter-spacing:2px;
}
`}</style>
</div>)
);
}
}
Header.propTypes = {
};

View File

@@ -1,23 +0,0 @@
{
"name": "header",
"version": "0.0.0",
"private": true,
"main": "./index",
"author": {
"name": "Don Strawsburg",
"email": "don@goforward.group",
"url": "https://goforward.group/"
},
"contributors": [
{
"name": "Don Strawsburg",
"email": "don@goforward.group",
"url": "https://goforward.group/"
},
{
"name": "Sean Strawsburg",
"email": "sean@goforward.group",
"url": "https://goforward.group/"
}
]
}

View File

@@ -1,13 +0,0 @@
.navLinks {
color:white;
text-transform: uppercase;
letter-spacing: 2px;
font-weight: bold;
transition: all 500ms ease;
}
.navLinks:hover {
text-decoration : none;
}
.nav-item:hover {
background-color: pink;
}

View File

@@ -1,45 +0,0 @@
import React from 'react';
import Typography from '@mui/material/Typography';
import MuiLink from '@mui/material/Link';
import Button from '@mui/material/Button';
export default class Hero extends React.Component {
constructor(props) {
super(props);
this.state = {
show: true,
};
}
render() {
return (
<div className="hero" styles={{ backgroundImage:`url({${this.props.image}})` }}>
<div className="hero-text">
<h3>{this.props.heading}</h3>
<p>{this.props.subheading}</p>
<Button href={this.props.link} variant="contained" color="primary">
{this.props.linktext}
</Button>
</div>
<style jsx>{`
.hero {
// background:url('/gb-hero.jpg');
background-size:cover;
min-height:35vw;
color: #fff;
display:flex;
justify-content: center;
flex-direction: column;
}
.hero-text {
padding: 2em;
}
`}</style>
</div>
);
}
}

View File

@@ -1,23 +0,0 @@
{
"name": "hero",
"version": "0.0.0",
"private": true,
"main": "./index",
"author": {
"name": "Don Strawsburg",
"email": "don@goforward.group",
"url": "https://goforward.group/"
},
"contributors": [
{
"name": "Don Strawsburg",
"email": "don@goforward.group",
"url": "https://goforward.group/"
},
{
"name": "Sean Strawsburg",
"email": "sean@goforward.group",
"url": "https://goforward.group/"
}
]
}

View File

@@ -1,35 +0,0 @@
import React, { Component } from 'react'
import PropTypes from 'prop-types' //ES6
import styles from './styles.module.css'
import { useQuery, useMutation, gql } from "@apollo/client";
export default function About(props) {
const GET_SITE_CONTENT = gql`
query Get_Site_Content {
site_contents(where: {content_id: {_eq: "ABOUTUS"}}, order_by: {content: asc}) {
id
content_id
content
}
}
`;
const { loading, error, data } = useQuery(GET_SITE_CONTENT);
if (loading) return "Loading ...";
if (error) return `Error! ${error.message}`;
return (
<div >
<h1>About</h1>
{data.site_contents.map((site_content: { content: any; }) => (
<span dangerouslySetInnerHTML={{ __html: site_content.content }} />
))}
</div>
)
}
About.propTypes = {
};

View File

@@ -1,23 +0,0 @@
{
"name": "about",
"version": "0.0.0",
"private": true,
"main": "./index",
"author": {
"name": "Don Strawsburg",
"email": "don@goforward.group",
"url": "https://goforward.group/"
},
"contributors": [
{
"name": "Don Strawsburg",
"email": "don@goforward.group",
"url": "https://goforward.group/"
},
{
"name": "Sean Strawsburg",
"email": "sean@goforward.group",
"url": "https://goforward.group/"
}
]
}

View File

@@ -1,39 +0,0 @@
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 '@/src/app/lib/constants'
import { useQuery, useMutation, gql } from "@apollo/client";
export default function ContactUs(props) {
const GET_SITE_CONTENT = gql`
query Get_Site_Content {
site_contents(where: {content_id: {_eq: "CONTACTUS"}}, order_by: {content: asc}) {
id
content_id
content
}
}
`;
const { loading, error, data } = useQuery(GET_SITE_CONTENT);
if (loading) return "Loading ...";
if (error) return `Error! ${error.message}`;
return (
<div>
<TypoGraphy paragraph='true' variant="body" color="inherit" >
{data.site_contents.map((site_content: { content: any; }) => (
<span dangerouslySetInnerHTML={{ __html: site_content.content }} />
))}
</TypoGraphy>
</div>
)
}
ContactUs.propTypes = {
};

View File

@@ -1,23 +0,0 @@
{
"name": "contactus",
"version": "0.0.0",
"private": true,
"main": "./index",
"author": {
"name": "Don Strawsburg",
"email": "don@goforward.group",
"url": "https://goforward.group/"
},
"contributors": [
{
"name": "Don Strawsburg",
"email": "don@goforward.group",
"url": "https://goforward.group/"
},
{
"name": "Sean Strawsburg",
"email": "sean@goforward.group",
"url": "https://goforward.group/"
}
]
}

View File

@@ -1,40 +0,0 @@
import React, { Component } from 'react';
import { COMPANY_NAME, COMPANY_URL } from '@/src/app/lib/constants';
import Typography from '@mui/material/Typography';
import MuiLink from '@mui/material/Link';
import styles from './styles.module.css'
import Link from 'next/link'
import styled from '@emotion/styled'
export default class Copyright extends Component {
render() {
return (
(<CopyStyled>
<div className="copyright">&copy;&nbsp; {new Date().getFullYear()} {' '}
<Link href={COMPANY_URL}>
{COMPANY_NAME}
</Link>{' '}
<span>All Rights Reserved.</span>
</div>
</CopyStyled>)
);
}
}
const CopyStyled = styled.div`
.copyright {
background: #4c5c3f;
font-size:.80em;
text-transform: uppercase;
color:#FFF;
display: block;
width:100%;
text-align:center;
a {
color:#FFF;
text-decoration:none;
}
}
`

View File

@@ -1,23 +0,0 @@
{
"name": "copyright",
"version": "0.0.0",
"private": true,
"main": "./index",
"author": {
"name": "Don Strawsburg",
"email": "don@goforward.group",
"url": "https://goforward.group/"
},
"contributors": [
{
"name": "Don Strawsburg",
"email": "don@goforward.group",
"url": "https://goforward.group/"
},
{
"name": "Sean Strawsburg",
"email": "sean@goforward.group",
"url": "https://goforward.group/"
}
]
}

View File

@@ -1,7 +0,0 @@
.white {
color: white;
font-size: .5em;
text-transform: uppercase;
letter-spacing: 2px;
font-family: "hind";
}

View File

@@ -1,54 +0,0 @@
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 '@/src/app/lib/constants'
import {SITE_CONT_TYPE} from '@/src/app/lib/constants'
import { useQuery, useMutation, gql } from "@apollo/client";
export default function Disclosure(props) {
const GET_SITE_CONTENT = gql`
query Get_Site_Content {
site_contents(where: {content_id: {_eq: ${SITE_CONT_TYPE.DISCLOSURE}}}, order_by: {content: asc}) {
id
content_id
content
}
}
`;
const { loading, error, data } = useQuery(GET_SITE_CONTENT);
if (loading) return "Loading ...";
if (error) return `Error! ${error.message}`;
return (
<div>
<TypoGraphy paragraph={true} variant="body1" color="inherit" >
{constants.SITE_NAME}, owned by {constants.COMPANY_NAME}, receives compensation through affiliate relationships with merchants listed on this site. Please know that this in no way affects reviews, benchmarks, content, or this site's opinions of products, services, manufacturers, partners, or merchants.
</TypoGraphy>
<TypoGraphy paragraph={true} variant="body1" color="inherit" >
The mission of {constants.SITE_NAME} is to provide the best functionality for this site's users, regardless of any potential affiliate commissions.
{constants.SITE_NAME} does not accept donations. Instead, income received from affiliate relationships funds site maintenance and feature development. If you desire to donate to PCPartPicker, I kindly ask that you consider donating to a charitable organization instead. I am particularly fond of the NRA, a non-profit organization that provides safety training to gun owners.
</TypoGraphy>
<div>
{data.site_contents.map((site_content: { content: any; }) => (
<span dangerouslySetInnerHTML={{ __html: site_content.content }} />
))}
</div>
<TypoGraphy paragraph={true} variant="body1" color="inherit" >
Thanks,
</TypoGraphy>
<TypoGraphy paragraph={true} variant="body1" color="inherit" >
{constants.COMPANY_NAME}
</TypoGraphy>
<TypoGraphy paragraph={true} variant="body1" color="inherit" >
{constants.SITE_NAME} is a participant in the Amazon Services LLC Associates Program, an affiliate advertising program designed to provide a means for sites to earn advertising fees by advertising and linking to amazon.com.
</TypoGraphy>
</div>
)
}
Disclosure.propTypes = {
};

View File

@@ -1,23 +0,0 @@
{
"name": "disclosure",
"version": "0.0.0",
"private": true,
"main": "./index",
"author": {
"name": "Don Strawsburg",
"email": "don@goforward.group",
"url": "https://goforward.group/"
},
"contributors": [
{
"name": "Don Strawsburg",
"email": "don@goforward.group",
"url": "https://goforward.group/"
},
{
"name": "Sean Strawsburg",
"email": "sean@goforward.group",
"url": "https://goforward.group/"
}
]
}

View File

@@ -1,34 +0,0 @@
import React, { Component } from 'react';
import styles from './styles.module.css'
import { useQuery, useMutation, gql } from "@apollo/client";
export default function Faq(props) {
const GET_SITE_CONTENT_FAQ = gql`
query Get_Site_Content_Faq {
site_contents(where: {content_id: {_eq: "FAQ"}}, order_by: {content: asc}) {
id
content_id
content
}
}
`;
const { loading, error, data } = useQuery(GET_SITE_CONTENT_FAQ);
if(loading) return "Loading ...";
if(error) return `Error! ${error.message}` ;
return (
<div className="faq container">
{props.children}
<h3>Frequently Asked Questions</h3>
<div>
{data.site_contents.map((site_content: { content: any; }) => (
<span dangerouslySetInnerHTML={{__html: site_content.content}}/>
))}
</div>
</div>
)
}

View File

@@ -1,23 +0,0 @@
{
"name": "faq",
"version": "0.0.0",
"private": true,
"main": "./index",
"author": {
"name": "Don Strawsburg",
"email": "don@goforward.group",
"url": "https://goforward.group/"
},
"contributors": [
{
"name": "Don Strawsburg",
"email": "don@goforward.group",
"url": "https://goforward.group/"
},
{
"name": "Sean Strawsburg",
"email": "sean@goforward.group",
"url": "https://goforward.group/"
}
]
}

View File

@@ -1,39 +0,0 @@
import React, { Component } from 'react'
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 '@/src/app/lib/constants'
import { useQuery, useMutation, gql } from "@apollo/client";
export default function PIP(props) {
const GET_SITE_CONTENT = gql`
query Get_Site_Content {
site_contents(where: {content_id: {_eq: "PIP"}}, order_by: {content: asc}) {
id
content_id
content
}
}
`;
const { loading, error, data } = useQuery(GET_SITE_CONTENT);
if (loading) return "Loading ...";
if (error) return `Error! ${error.message}`;
return (
<div>
<Head title="Personal Information" />
<TypoGraphy paragraph='true' variant="body" color="inherit" >
{data.site_contents.map((site_content: { content: any; }) => (
<span dangerouslySetInnerHTML={{ __html: site_content.content }} />
))}
</TypoGraphy>
</div>
)
}
PIP.propTypes = {
};

View File

@@ -1,23 +0,0 @@
{
"name": "pip",
"version": "0.0.0",
"private": true,
"main": "./index",
"author": {
"name": "Don Strawsburg",
"email": "don@goforward.group",
"url": "https://goforward.group/"
},
"contributors": [
{
"name": "Don Strawsburg",
"email": "don@goforward.group",
"url": "https://goforward.group/"
},
{
"name": "Sean Strawsburg",
"email": "sean@goforward.group",
"url": "https://goforward.group/"
}
]
}

View File

@@ -1,35 +0,0 @@
import React, { Component } from 'react'
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 '@/src/app/lib/constants'
import { useQuery, useMutation, gql } from "@apollo/client";
export default function PrivacyPolicy(props) {
const GET_SITE_CONTENT = gql`
query Get_Site_Content {
site_contents(where: {content_id: {_eq: "PP"}}, order_by: {content: asc}) {
id
content_id
content
}
}
`;
const { loading, error, data } = useQuery(GET_SITE_CONTENT);
if (loading) return "Loading ...";
if (error) return `Error! ${error.message}`;
return (
<div>
<Head title="Privacy Policy" />
<TypoGraphy paragraph='true' variant="body" color="inherit" >
{data.site_contents.map((site_content: { content: any; }) => (
<span dangerouslySetInnerHTML={{ __html: site_content.content }} />
))}
</TypoGraphy>
</div>
)
}

View File

@@ -1,23 +0,0 @@
{
"name": "privacypolicy",
"version": "0.0.0",
"private": true,
"main": "./index",
"author": {
"name": "Don Strawsburg",
"email": "don@goforward.group",
"url": "https://goforward.group/"
},
"contributors": [
{
"name": "Don Strawsburg",
"email": "don@goforward.group",
"url": "https://goforward.group/"
},
{
"name": "Sean Strawsburg",
"email": "sean@goforward.group",
"url": "https://goforward.group/"
}
]
}

View File

@@ -1,38 +0,0 @@
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 '@/src/app/lib/constants'
import { useQuery, useMutation, gql } from "@apollo/client";
export default function TermsOfService(props) {
const GET_SITE_CONTENT = gql`
query Get_Site_Content {
site_contents(where: {content_id: {_eq: "TOS"}}, order_by: {content: asc}) {
id
content_id
content
}
}
`;
const { loading, error, data } = useQuery(GET_SITE_CONTENT);
if (loading) return "Loading ...";
if (error) return `Error! ${error.message}`;
return (
<div>
<Head title="Terms Of Service" />
<TypoGraphy paragraph='true' variant="body" color="inherit" >
<div>
{data.site_contents.map((site_content: { content: any; }) => (
<span dangerouslySetInnerHTML={{ __html: site_content.content }} />
))}
</div>
</TypoGraphy>
</div>
)
}
TermsOfService.propTypes = {
};

View File

@@ -1,23 +0,0 @@
{
"name": "termsofservice",
"version": "0.0.0",
"private": true,
"main": "./index.tsx",
"author": {
"name": "Don Strawsburg",
"email": "don@goforward.group",
"url": "https://goforward.group/"
},
"contributors": [
{
"name": "Don Strawsburg",
"email": "don@goforward.group",
"url": "https://goforward.group/"
},
{
"name": "Sean Strawsburg",
"email": "sean@goforward.group",
"url": "https://goforward.group/"
}
]
}

View File

@@ -1,132 +0,0 @@
import React from 'react';
import Avatar from '@mui/material/Avatar';
import Button from '@mui/material/Button';
import CssBaseline from '@mui/material/CssBaseline';
import TextField from '@mui/material/TextField';
import FormControlLabel from '@mui/material/FormControlLabel';
import Checkbox from '@mui/material/Checkbox';
import Link from '@mui/material/Link';
import Paper from '@mui/material/Paper';
import Box from '@mui/material/Box';
import Grid from '@mui/material/Grid';
import LockOutlinedIcon from '@material-ui/icons/LockOutlined';
import Typography from '@mui/material/Typography';
import { makeStyles } from '@mui/material/styles';
import styles from "./styles.module.css";
function Copyright() {
return (
<Typography variant="body2" color="textSecondary" align="center">
{'Copyright © '}
<Link color="inherit" href="https://material-ui.com/">
Your Website
</Link>{' '}
{new Date().getFullYear()}
{'.'}
</Typography>
);
}
const useStyles = makeStyles((theme) => ({
root: {
height: '100vh',
},
image: {
backgroundImage: 'url(https://source.unsplash.com/random)',
backgroundRepeat: 'no-repeat',
backgroundColor:
theme.palette.type === 'light' ? theme.palette.grey[50] : theme.palette.grey[900],
backgroundSize: 'cover',
backgroundPosition: 'center',
},
paper: {
margin: theme.spacing(8, 4),
display: 'flex',
flexDirection: 'column',
alignItems: 'center',
},
avatar: {
margin: theme.spacing(1),
backgroundColor: theme.palette.secondary.main,
},
form: {
width: '100%', // Fix IE 11 issue.
marginTop: theme.spacing(1),
},
submit: {
margin: theme.spacing(3, 0, 2),
},
}));
export default function SignInSide() {
const classes = useStyles();
return (
<Grid container component="main" className={classes.root}>
<CssBaseline />
<Grid item xs={false} sm={4} md={7} className={classes.image} />
<Grid item xs={12} sm={8} md={5} component={Paper} elevation={6} square>
<div className={classes.paper}>
<Avatar className={classes.avatar}>
<LockOutlinedIcon />
</Avatar>
<Typography component="h1" variant="h5">
Sign in
</Typography>
<form className={classes.form} noValidate>
<TextField
variant="outlined"
margin="normal"
required
fullWidth
id="email"
label="Email Address"
name="email"
autoComplete="email"
autoFocus
/>
<TextField
variant="outlined"
margin="normal"
required
fullWidth
name="password"
label="Password"
type="password"
id="password"
autoComplete="current-password"
/>
<FormControlLabel
control={<Checkbox value="remember" color="primary" />}
label="Remember me"
/>
<Button
type="submit"
fullWidth
variant="contained"
color="primary"
className={classes.submit}
>
Sign In
</Button>
<Grid container>
<Grid item xs>
<Link href="#" variant="body2">
Forgot password?
</Link>
</Grid>
<Grid item>
<Link href="#" variant="body2">
{"Don't have an account? Sign Up"}
</Link>
</Grid>
</Grid>
<Box mt={5}>
<Copyright />
</Box>
</form>
</div>
</Grid>
</Grid>
);
}

View File

@@ -1,23 +0,0 @@
{
"name": "signin",
"version": "0.0.0",
"private": true,
"main": "./index",
"author": {
"name": "Don Strawsburg",
"email": "don@goforward.group",
"url": "https://goforward.group/"
},
"contributors": [
{
"name": "Don Strawsburg",
"email": "don@goforward.group",
"url": "https://goforward.group/"
},
{
"name": "Sean Strawsburg",
"email": "sean@goforward.group",
"url": "https://goforward.group/"
}
]
}

View File

@@ -1,39 +0,0 @@
import { Box, Flex, Link, Heading } from "@chakra-ui/react";
import NextLink from "next/link";
const Header: React.FC = () => {
return (
<>
<Box as="header" bg="primary" color="white" px="6" py="4" shadow="md">
<Flex justify="space-between" align="center" maxW="5xl" mx="auto">
<Heading as="h1" size="lg">
<NextLink href="/" passHref>
<Link color="white" _hover={{ textDecoration: "none" }}>
Ballistic Builder
</Link>
</NextLink>
</Heading>
<Flex as="nav" gap="6">
<NextLink href="/builder" passHref>
<Link color="white" _hover={{ textDecoration: "underline" }}>
Builder
</Link>
</NextLink>
<NextLink href="/products" passHref>
<Link color="white" _hover={{ textDecoration: "underline" }}>
Products
</Link>
</NextLink>
<NextLink href="/auth/signin" passHref>
<Link color="white" _hover={{ textDecoration: "underline" }}>
Sign In
</Link>
</NextLink>
</Flex>
</Flex>
</Box>
</>
);
};
export default Header;

View File

@@ -1,23 +0,0 @@
import Link from "next/link";
export default function Header() {
{/* Header Section */ }
return (
(
<header className="bg-gray-800 text-white py-4 shadow-md">
<div className="container mx-auto px-6 flex justify-between items-center">
<h1 className="text-2xl font-bold">Ballistic Builder</h1>
<nav>
<ul className="flex space-x-4">
<li><Link href="#features" className="hover:underline">Features</Link></li>
<li><Link href="/builder" className="hover:underline">Builder</Link></li>
<li><Link href="/products" className="hover:underline">Products</Link></li>
<li><Link href="#contact" className="hover:underline">Contact</Link></li>
</ul>
</nav>
</div>
</header>
)
)}

View File

@@ -1,24 +0,0 @@
import Link from "next/link";
export default function Hero() {
{/* Hero Section */ }
return (
<section className="bg-gray-700 text-white py-20 text-center">
<div className="container mx-auto px-6">
<h2 className="text-4xl font-bold mb-4">Build Your Dream Firearm</h2>
<p className="text-lg mb-6">
Customize every component of your firearm with ease and precision.
</p>
<Link
href="/builder"
className="bg-blue-500 hover:bg-blue-700 text-white font-bold py-2 px-4 rounded">
Get Started
</Link>
</div>
</section>
)
}

View File

@@ -1,24 +0,0 @@
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 (
(
<>
<Header />
<Hero />
<FeaturesSection />
<About />
<Contact />
<Footer />
</>
)
)
}

View File

@@ -1,47 +0,0 @@
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 (
<Accordion.ItemTrigger {...rest} ref={ref}>
{indicatorPlacement === "start" && (
<Accordion.ItemIndicator rotate={{ base: "-90deg", _open: "0deg" }}>
<LuChevronDown />
</Accordion.ItemIndicator>
)}
<HStack gap="4" flex="1" textAlign="start" width="full">
{children}
</HStack>
{indicatorPlacement === "end" && (
<Accordion.ItemIndicator>
<LuChevronDown />
</Accordion.ItemIndicator>
)}
</Accordion.ItemTrigger>
)
})
interface AccordionItemContentProps extends Accordion.ItemContentProps {}
export const AccordionItemContent = React.forwardRef<
HTMLDivElement,
AccordionItemContentProps
>(function AccordionItemContent(props, ref) {
return (
<Accordion.ItemContent>
<Accordion.ItemBody {...props} ref={ref} />
</Accordion.ItemContent>
)
})
export const AccordionRoot = Accordion.Root
export const AccordionItem = Accordion.Item

View File

@@ -1,40 +0,0 @@
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<HTMLElement>
}
export const ActionBarContent = React.forwardRef<
HTMLDivElement,
ActionBarContentProps
>(function ActionBarContent(props, ref) {
const { children, portalled = true, portalRef, ...rest } = props
return (
<Portal disabled={!portalled} container={portalRef}>
<ActionBar.Positioner>
<ActionBar.Content ref={ref} {...rest} asChild={false}>
{children}
</ActionBar.Content>
</ActionBar.Positioner>
</Portal>
)
})
export const ActionBarCloseTrigger = React.forwardRef<
HTMLButtonElement,
ActionBar.CloseTriggerProps
>(function ActionBarCloseTrigger(props, ref) {
return (
<ActionBar.CloseTrigger {...props} asChild ref={ref}>
<CloseButton size="sm" />
</ActionBar.CloseTrigger>
)
})
export const ActionBarRoot = ActionBar.Root
export const ActionBarSelectionTrigger = ActionBar.SelectionTrigger
export const ActionBarSeparator = ActionBar.Separator

View File

@@ -1,51 +0,0 @@
import { Alert as ChakraAlert } from "@chakra-ui/react"
import { CloseButton } from "./close-button"
import * as React from "react"
export interface AlertProps extends Omit<ChakraAlert.RootProps, "title"> {
startElement?: React.ReactNode
endElement?: React.ReactNode
title?: React.ReactNode
icon?: React.ReactElement
closable?: boolean
onClose?: () => void
}
export const Alert = React.forwardRef<HTMLDivElement, AlertProps>(
function Alert(props, ref) {
const {
title,
children,
icon,
closable,
onClose,
startElement,
endElement,
...rest
} = props
return (
<ChakraAlert.Root ref={ref} {...rest}>
{startElement || <ChakraAlert.Indicator>{icon}</ChakraAlert.Indicator>}
{children ? (
<ChakraAlert.Content>
<ChakraAlert.Title>{title}</ChakraAlert.Title>
<ChakraAlert.Description>{children}</ChakraAlert.Description>
</ChakraAlert.Content>
) : (
<ChakraAlert.Title flex="1">{title}</ChakraAlert.Title>
)}
{endElement}
{closable && (
<CloseButton
size="sm"
pos="relative"
top="-2"
insetEnd="-2"
alignSelf="flex-start"
onClick={onClose}
/>
)}
</ChakraAlert.Root>
)
},
)

View File

@@ -1,74 +0,0 @@
"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<HTMLImageElement>
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<HTMLDivElement, AvatarProps>(
function Avatar(props, ref) {
const { name, src, srcSet, loading, icon, fallback, children, ...rest } =
props
return (
<ChakraAvatar.Root ref={ref} {...rest}>
<AvatarFallback name={name} icon={icon}>
{fallback}
</AvatarFallback>
<ChakraAvatar.Image src={src} srcSet={srcSet} loading={loading} />
{children}
</ChakraAvatar.Root>
)
},
)
interface AvatarFallbackProps extends ChakraAvatar.FallbackProps {
name?: string
icon?: React.ReactElement
}
const AvatarFallback = React.forwardRef<HTMLDivElement, AvatarFallbackProps>(
function AvatarFallback(props, ref) {
const { name, icon, children, ...rest } = props
return (
<ChakraAvatar.Fallback ref={ref} {...rest}>
{children}
{name != null && children == null && <>{getInitials(name)}</>}
{name == null && children == null && (
<ChakraAvatar.Icon asChild={!!icon}>{icon}</ChakraAvatar.Icon>
)}
</ChakraAvatar.Fallback>
)
},
)
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<HTMLDivElement, AvatarGroupProps>(
function AvatarGroup(props, ref) {
const { size, variant, borderless, ...rest } = props
return (
<ChakraAvatar.PropsProvider value={{ size, variant, borderless }}>
<Group gap="0" spaceX="-3" ref={ref} {...rest} />
</ChakraAvatar.PropsProvider>
)
},
)

View File

@@ -1,31 +0,0 @@
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<HTMLDivElement, BlockquoteProps>(
function Blockquote(props, ref) {
const { children, cite, citeUrl, showDash, icon, ...rest } = props
return (
<ChakraBlockquote.Root ref={ref} {...rest}>
{icon}
<ChakraBlockquote.Content cite={citeUrl}>
{children}
</ChakraBlockquote.Content>
{cite && (
<ChakraBlockquote.Caption>
{showDash ? <>&mdash;</> : null} <cite>{cite}</cite>
</ChakraBlockquote.Caption>
)}
</ChakraBlockquote.Root>
)
},
)
export const BlockquoteIcon = ChakraBlockquote.Icon

View File

@@ -1,40 +0,0 @@
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 (
<Breadcrumb.Root ref={ref} {...rest}>
<Breadcrumb.List gap={separatorGap}>
{validChildren.map((child, index) => {
const last = index === validChildren.length - 1
return (
<React.Fragment key={index}>
<Breadcrumb.Item>{child}</Breadcrumb.Item>
{!last && (
<Breadcrumb.Separator>{separator}</Breadcrumb.Separator>
)}
</React.Fragment>
)
})}
</Breadcrumb.List>
</Breadcrumb.Root>
)
})
export const BreadcrumbLink = Breadcrumb.Link
export const BreadcrumbCurrentLink = Breadcrumb.CurrentLink
export const BreadcrumbEllipsis = Breadcrumb.Ellipsis

View File

@@ -1,40 +0,0 @@
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<HTMLButtonElement, ButtonProps>(
function Button(props, ref) {
const { loading, disabled, loadingText, children, ...rest } = props
return (
<ChakraButton disabled={loading || disabled} ref={ref} {...rest}>
{loading && !loadingText ? (
<>
<AbsoluteCenter display="inline-flex">
<Spinner size="inherit" color="inherit" />
</AbsoluteCenter>
<Span opacity={0}>{children}</Span>
</>
) : loading && loadingText ? (
<>
<Spinner size="inherit" color="inherit" />
{loadingText}
</>
) : (
children
)}
</ChakraButton>
)
},
)

View File

@@ -1,58 +0,0 @@
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<HTMLInputElement>
}
export const CheckboxCard = React.forwardRef<
HTMLInputElement,
CheckboxCardProps
>(function CheckboxCard(props, ref) {
const {
inputProps,
label,
description,
icon,
addon,
indicator = <ChakraCheckboxCard.Indicator />,
indicatorPlacement = "end",
...rest
} = props
const hasContent = label || description || icon
const ContentWrapper = indicator ? ChakraCheckboxCard.Content : React.Fragment
return (
<ChakraCheckboxCard.Root {...rest}>
<ChakraCheckboxCard.HiddenInput ref={ref} {...inputProps} />
<ChakraCheckboxCard.Control>
{indicatorPlacement === "start" && indicator}
{hasContent && (
<ContentWrapper>
{icon}
{label && (
<ChakraCheckboxCard.Label>{label}</ChakraCheckboxCard.Label>
)}
{description && (
<ChakraCheckboxCard.Description>
{description}
</ChakraCheckboxCard.Description>
)}
{indicatorPlacement === "inside" && indicator}
</ContentWrapper>
)}
{indicatorPlacement === "end" && indicator}
</ChakraCheckboxCard.Control>
{addon && <ChakraCheckboxCard.Addon>{addon}</ChakraCheckboxCard.Addon>}
</ChakraCheckboxCard.Root>
)
})
export const CheckboxCardIndicator = ChakraCheckboxCard.Indicator

View File

@@ -1,25 +0,0 @@
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<HTMLInputElement>
rootRef?: React.Ref<HTMLLabelElement>
}
export const Checkbox = React.forwardRef<HTMLInputElement, CheckboxProps>(
function Checkbox(props, ref) {
const { icon, children, inputProps, rootRef, ...rest } = props
return (
<ChakraCheckbox.Root ref={rootRef} {...rest}>
<ChakraCheckbox.HiddenInput ref={ref} {...inputProps} />
<ChakraCheckbox.Control>
{icon || <ChakraCheckbox.Indicator />}
</ChakraCheckbox.Control>
{children != null && (
<ChakraCheckbox.Label>{children}</ChakraCheckbox.Label>
)}
</ChakraCheckbox.Root>
)
},
)

View File

@@ -1,108 +0,0 @@
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 (
<ChakraClipboard.Indicator copied={<LuCheck />} {...props} ref={ref}>
<LuClipboard />
</ChakraClipboard.Indicator>
)
})
const ClipboardCopyText = React.forwardRef<
HTMLDivElement,
ChakraClipboard.IndicatorProps
>(function ClipboardCopyText(props, ref) {
return (
<ChakraClipboard.Indicator copied="Copied" {...props} ref={ref}>
Copy
</ChakraClipboard.Indicator>
)
})
export const ClipboardLabel = React.forwardRef<
HTMLLabelElement,
ChakraClipboard.LabelProps
>(function ClipboardLabel(props, ref) {
return (
<ChakraClipboard.Label
textStyle="sm"
fontWeight="medium"
display="inline-block"
mb="1"
{...props}
ref={ref}
/>
)
})
export const ClipboardButton = React.forwardRef<HTMLButtonElement, ButtonProps>(
function ClipboardButton(props, ref) {
return (
<ChakraClipboard.Trigger asChild>
<Button ref={ref} size="sm" variant="surface" {...props}>
<ClipboardIcon />
<ClipboardCopyText />
</Button>
</ChakraClipboard.Trigger>
)
},
)
export const ClipboardLink = React.forwardRef<HTMLButtonElement, ButtonProps>(
function ClipboardLink(props, ref) {
return (
<ChakraClipboard.Trigger asChild>
<Button
unstyled
variant="plain"
size="xs"
display="inline-flex"
alignItems="center"
gap="2"
ref={ref}
{...props}
>
<LuLink />
<ClipboardCopyText />
</Button>
</ChakraClipboard.Trigger>
)
},
)
export const ClipboardIconButton = React.forwardRef<
HTMLButtonElement,
ButtonProps
>(function ClipboardIconButton(props, ref) {
return (
<ChakraClipboard.Trigger asChild>
<IconButton ref={ref} size="xs" variant="subtle" {...props}>
<ClipboardIcon />
<ClipboardCopyText srOnly />
</IconButton>
</ChakraClipboard.Trigger>
)
})
export const ClipboardInput = React.forwardRef<HTMLInputElement, InputProps>(
function ClipboardInputElement(props, ref) {
return (
<ChakraClipboard.Input asChild>
<Input ref={ref} {...props} />
</ChakraClipboard.Input>
)
},
)
export const ClipboardRoot = ChakraClipboard.Root

View File

@@ -1,17 +0,0 @@
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 (
<ChakraIconButton variant="ghost" aria-label="Close" ref={ref} {...props}>
{props.children ?? <LuX />}
</ChakraIconButton>
)
})

View File

@@ -1,67 +0,0 @@
"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 (
<ThemeProvider attribute="class" disableTransitionOnChange {...props} />
)
}
export function useColorMode() {
const { resolvedTheme, setTheme } = useTheme()
const toggleColorMode = () => {
setTheme(resolvedTheme === "light" ? "dark" : "light")
}
return {
colorMode: resolvedTheme,
setColorMode: setTheme,
toggleColorMode,
}
}
export function useColorModeValue<T>(light: T, dark: T) {
const { colorMode } = useColorMode()
return colorMode === "light" ? light : dark
}
export function ColorModeIcon() {
const { colorMode } = useColorMode()
return colorMode === "light" ? <LuSun /> : <LuMoon />
}
interface ColorModeButtonProps extends Omit<IconButtonProps, "aria-label"> {}
export const ColorModeButton = React.forwardRef<
HTMLButtonElement,
ColorModeButtonProps
>(function ColorModeButton(props, ref) {
const { toggleColorMode } = useColorMode()
return (
<ClientOnly fallback={<Skeleton boxSize="8" />}>
<IconButton
onClick={toggleColorMode}
variant="ghost"
aria-label="Toggle color mode"
size="sm"
ref={ref}
{...props}
css={{
_icon: {
width: "5",
height: "5",
},
}}
>
<ColorModeIcon />
</IconButton>
</ClientOnly>
)
})

View File

@@ -1,30 +0,0 @@
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<HTMLDivElement, ItemProps>(
function DataListItem(props, ref) {
const { label, info, value, children, grow, ...rest } = props
return (
<ChakraDataList.Item ref={ref} {...rest}>
<ChakraDataList.ItemLabel flex={grow ? "1" : undefined}>
{label}
{info && <InfoTip>{info}</InfoTip>}
</ChakraDataList.ItemLabel>
<ChakraDataList.ItemValue flex={grow ? "1" : undefined}>
{value}
</ChakraDataList.ItemValue>
{children}
</ChakraDataList.Item>
)
},
)

View File

@@ -1,62 +0,0 @@
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<HTMLElement>
backdrop?: boolean
}
export const DialogContent = React.forwardRef<
HTMLDivElement,
DialogContentProps
>(function DialogContent(props, ref) {
const {
children,
portalled = true,
portalRef,
backdrop = true,
...rest
} = props
return (
<Portal disabled={!portalled} container={portalRef}>
{backdrop && <ChakraDialog.Backdrop />}
<ChakraDialog.Positioner>
<ChakraDialog.Content ref={ref} {...rest} asChild={false}>
{children}
</ChakraDialog.Content>
</ChakraDialog.Positioner>
</Portal>
)
})
export const DialogCloseTrigger = React.forwardRef<
HTMLButtonElement,
ChakraDialog.CloseTriggerProps
>(function DialogCloseTrigger(props, ref) {
return (
<ChakraDialog.CloseTrigger
position="absolute"
top="2"
insetEnd="2"
{...props}
asChild
>
<CloseButton size="sm" ref={ref}>
{props.children}
</CloseButton>
</ChakraDialog.CloseTrigger>
)
})
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

View File

@@ -1,52 +0,0 @@
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<HTMLElement>
offset?: ChakraDrawer.ContentProps["padding"]
}
export const DrawerContent = React.forwardRef<
HTMLDivElement,
DrawerContentProps
>(function DrawerContent(props, ref) {
const { children, portalled = true, portalRef, offset, ...rest } = props
return (
<Portal disabled={!portalled} container={portalRef}>
<ChakraDrawer.Positioner padding={offset}>
<ChakraDrawer.Content ref={ref} {...rest} asChild={false}>
{children}
</ChakraDrawer.Content>
</ChakraDrawer.Positioner>
</Portal>
)
})
export const DrawerCloseTrigger = React.forwardRef<
HTMLButtonElement,
ChakraDrawer.CloseTriggerProps
>(function DrawerCloseTrigger(props, ref) {
return (
<ChakraDrawer.CloseTrigger
position="absolute"
top="2"
insetEnd="2"
{...props}
asChild
>
<CloseButton size="sm" ref={ref} />
</ChakraDrawer.CloseTrigger>
)
})
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

View File

@@ -1,34 +0,0 @@
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<HTMLDivElement, EmptyStateProps>(
function EmptyState(props, ref) {
const { title, description, icon, children, ...rest } = props
return (
<ChakraEmptyState.Root ref={ref} {...rest}>
<ChakraEmptyState.Content>
{icon && (
<ChakraEmptyState.Indicator>{icon}</ChakraEmptyState.Indicator>
)}
{description ? (
<VStack textAlign="center">
<ChakraEmptyState.Title>{title}</ChakraEmptyState.Title>
<ChakraEmptyState.Description>
{description}
</ChakraEmptyState.Description>
</VStack>
) : (
<ChakraEmptyState.Title>{title}</ChakraEmptyState.Title>
)}
{children}
</ChakraEmptyState.Content>
</ChakraEmptyState.Root>
)
},
)

View File

@@ -1,33 +0,0 @@
import { Field as ChakraField } from "@chakra-ui/react"
import * as React from "react"
export interface FieldProps extends Omit<ChakraField.RootProps, "label"> {
label?: React.ReactNode
helperText?: React.ReactNode
errorText?: React.ReactNode
optionalText?: React.ReactNode
}
export const Field = React.forwardRef<HTMLDivElement, FieldProps>(
function Field(props, ref) {
const { label, children, helperText, errorText, optionalText, ...rest } =
props
return (
<ChakraField.Root ref={ref} {...rest}>
{label && (
<ChakraField.Label>
{label}
<ChakraField.RequiredIndicator fallback={optionalText} />
</ChakraField.Label>
)}
{children}
{helperText && (
<ChakraField.HelperText>{helperText}</ChakraField.HelperText>
)}
{errorText && (
<ChakraField.ErrorText>{errorText}</ChakraField.ErrorText>
)}
</ChakraField.Root>
)
},
)

View File

@@ -1,170 +0,0 @@
"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<HTMLInputElement>
}
export const FileUploadRoot = React.forwardRef<
HTMLInputElement,
FileUploadRootProps
>(function FileUploadRoot(props, ref) {
const { children, inputProps, ...rest } = props
return (
<ChakraFileUpload.Root {...rest}>
<ChakraFileUpload.HiddenInput ref={ref} {...inputProps} />
{children}
</ChakraFileUpload.Root>
)
})
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 (
<ChakraFileUpload.Dropzone ref={ref} {...rest}>
<Icon fontSize="xl" color="fg.muted">
<LuUpload />
</Icon>
<ChakraFileUpload.DropzoneContent>
<div>{label}</div>
{description && <Text color="fg.muted">{description}</Text>}
</ChakraFileUpload.DropzoneContent>
{children}
</ChakraFileUpload.Dropzone>
)
})
interface VisibilityProps {
showSize?: boolean
clearable?: boolean
}
interface FileUploadItemProps extends VisibilityProps {
file: File
}
const FileUploadItem = React.forwardRef<HTMLLIElement, FileUploadItemProps>(
function FileUploadItem(props, ref) {
const { file, showSize, clearable } = props
return (
<ChakraFileUpload.Item file={file} ref={ref}>
<ChakraFileUpload.ItemPreview asChild>
<Icon fontSize="lg" color="fg.muted">
<LuFile />
</Icon>
</ChakraFileUpload.ItemPreview>
{showSize ? (
<ChakraFileUpload.ItemContent>
<ChakraFileUpload.ItemName />
<ChakraFileUpload.ItemSizeText />
</ChakraFileUpload.ItemContent>
) : (
<ChakraFileUpload.ItemName flex="1" />
)}
{clearable && (
<ChakraFileUpload.ItemDeleteTrigger asChild>
<IconButton variant="ghost" color="fg.muted" size="xs">
<LuX />
</IconButton>
</ChakraFileUpload.ItemDeleteTrigger>
)}
</ChakraFileUpload.Item>
)
},
)
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 (
<ChakraFileUpload.ItemGroup ref={ref} {...rest}>
{acceptedFiles.map((file) => (
<FileUploadItem
key={file.name}
file={file}
showSize={showSize}
clearable={clearable}
/>
))}
</ChakraFileUpload.ItemGroup>
)
})
type Assign<T, U> = Omit<T, keyof U> & U
interface FileInputProps extends Assign<ButtonProps, RecipeProps<"input">> {
placeholder?: React.ReactNode
}
export const FileInput = React.forwardRef<HTMLButtonElement, FileInputProps>(
function FileInput(props, ref) {
const inputRecipe = useRecipe({ key: "input" })
const [recipeProps, restProps] = inputRecipe.splitVariantProps(props)
const { placeholder = "Select file(s)", ...rest } = restProps
return (
<ChakraFileUpload.Trigger asChild>
<Button
unstyled
py="0"
ref={ref}
{...rest}
css={[inputRecipe(recipeProps), props.css]}
>
<ChakraFileUpload.Context>
{({ acceptedFiles }) => {
if (acceptedFiles.length === 1) {
return <span>{acceptedFiles[0].name}</span>
}
if (acceptedFiles.length > 1) {
return <span>{acceptedFiles.length} files</span>
}
return <Span color="fg.subtle">{placeholder}</Span>
}}
</ChakraFileUpload.Context>
</Button>
</ChakraFileUpload.Trigger>
)
},
)
export const FileUploadLabel = ChakraFileUpload.Label
export const FileUploadClearTrigger = ChakraFileUpload.ClearTrigger
export const FileUploadTrigger = ChakraFileUpload.Trigger

View File

@@ -1,36 +0,0 @@
import { HoverCard, Portal } from "@chakra-ui/react"
import * as React from "react"
interface HoverCardContentProps extends HoverCard.ContentProps {
portalled?: boolean
portalRef?: React.RefObject<HTMLElement>
}
export const HoverCardContent = React.forwardRef<
HTMLDivElement,
HoverCardContentProps
>(function HoverCardContent(props, ref) {
const { portalled = true, portalRef, ...rest } = props
return (
<Portal disabled={!portalled} container={portalRef}>
<HoverCard.Positioner>
<HoverCard.Content ref={ref} {...rest} />
</HoverCard.Positioner>
</Portal>
)
})
export const HoverCardArrow = React.forwardRef<
HTMLDivElement,
HoverCard.ArrowProps
>(function HoverCardArrow(props, ref) {
return (
<HoverCard.Arrow ref={ref} {...props}>
<HoverCard.ArrowTip />
</HoverCard.Arrow>
)
})
export const HoverCardRoot = HoverCard.Root
export const HoverCardTrigger = HoverCard.Trigger

View File

@@ -1,50 +0,0 @@
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<HTMLDivElement, InputGroupProps>(
function InputGroup(props, ref) {
const {
startElement,
startElementProps,
endElement,
endElementProps,
children,
startOffset = "6px",
endOffset = "6px",
...rest
} = props
return (
<Group ref={ref} {...rest}>
{startElement && (
<InputElement pointerEvents="none" {...startElementProps}>
{startElement}
</InputElement>
)}
{React.cloneElement(children, {
...(startElement && {
ps: `calc(var(--input-height) - ${startOffset})`,
}),
...(endElement && { pe: `calc(var(--input-height) - ${endOffset})` }),
...children.props,
})}
{endElement && (
<InputElement placement="end" {...endElementProps}>
{endElement}
</InputElement>
)}
</Group>
)
},
)

View File

@@ -1,12 +0,0 @@
"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<HTMLAnchorElement, LinkButtonProps>("a")

View File

@@ -1,110 +0,0 @@
"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<HTMLElement>
}
export const MenuContent = React.forwardRef<HTMLDivElement, MenuContentProps>(
function MenuContent(props, ref) {
const { portalled = true, portalRef, ...rest } = props
return (
<Portal disabled={!portalled} container={portalRef}>
<ChakraMenu.Positioner>
<ChakraMenu.Content ref={ref} {...rest} />
</ChakraMenu.Positioner>
</Portal>
)
},
)
export const MenuArrow = React.forwardRef<
HTMLDivElement,
ChakraMenu.ArrowProps
>(function MenuArrow(props, ref) {
return (
<ChakraMenu.Arrow ref={ref} {...props}>
<ChakraMenu.ArrowTip />
</ChakraMenu.Arrow>
)
})
export const MenuCheckboxItem = React.forwardRef<
HTMLDivElement,
ChakraMenu.CheckboxItemProps
>(function MenuCheckboxItem(props, ref) {
return (
<ChakraMenu.CheckboxItem ref={ref} {...props}>
<ChakraMenu.ItemIndicator hidden={false}>
<LuCheck />
</ChakraMenu.ItemIndicator>
{props.children}
</ChakraMenu.CheckboxItem>
)
})
export const MenuRadioItem = React.forwardRef<
HTMLDivElement,
ChakraMenu.RadioItemProps
>(function MenuRadioItem(props, ref) {
const { children, ...rest } = props
return (
<ChakraMenu.RadioItem ps="8" ref={ref} {...rest}>
<AbsoluteCenter axis="horizontal" left="4" asChild>
<ChakraMenu.ItemIndicator>
<LuCheck />
</ChakraMenu.ItemIndicator>
</AbsoluteCenter>
<ChakraMenu.ItemText>{children}</ChakraMenu.ItemText>
</ChakraMenu.RadioItem>
)
})
export const MenuItemGroup = React.forwardRef<
HTMLDivElement,
ChakraMenu.ItemGroupProps
>(function MenuItemGroup(props, ref) {
const { title, children, ...rest } = props
return (
<ChakraMenu.ItemGroup ref={ref} {...rest}>
{title && (
<ChakraMenu.ItemGroupLabel userSelect="none">
{title}
</ChakraMenu.ItemGroupLabel>
)}
{children}
</ChakraMenu.ItemGroup>
)
})
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 (
<ChakraMenu.TriggerItem ref={ref} {...rest}>
{startIcon}
{children}
<LuChevronRight />
</ChakraMenu.TriggerItem>
)
})
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

View File

@@ -1,57 +0,0 @@
"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 (
<Select.Root ref={ref} {...rest}>
{children}
<Select.Indicator>{icon}</Select.Indicator>
</Select.Root>
)
})
interface NativeSelectItem {
value: string
label: string
disabled?: boolean
}
interface NativeSelectField extends Select.FieldProps {
items?: Array<string | NativeSelectItem>
}
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 (
<Select.Field ref={ref} {...rest}>
{children}
{items?.map((item) => (
<option key={item.value} value={item.value} disabled={item.disabled}>
{item.label}
</option>
))}
</Select.Field>
)
})

View File

@@ -1,24 +0,0 @@
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 (
<ChakraNumberInput.Root ref={ref} variant="outline" {...rest}>
{children}
<ChakraNumberInput.Control>
<ChakraNumberInput.IncrementTrigger />
<ChakraNumberInput.DecrementTrigger />
</ChakraNumberInput.Control>
</ChakraNumberInput.Root>
)
})
export const NumberInputField = ChakraNumberInput.Input
export const NumberInputScruber = ChakraNumberInput.Scrubber
export const NumberInputLabel = ChakraNumberInput.Label

View File

@@ -1,208 +0,0 @@
"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<ButtonVariantContext>({
name: "RootPropsProvider",
})
export interface PaginationRootProps
extends Omit<ChakraPagination.RootProps, "type"> {
size?: ButtonProps["size"]
variant?: PaginationVariant
getHref?: (page: number) => string
}
const variantMap: Record<PaginationVariant, ButtonVariantMap> = {
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 (
<RootPropsProvider
value={{ size, variantMap: variantMap[variant], getHref }}
>
<ChakraPagination.Root
ref={ref}
type={getHref ? "link" : "button"}
{...rest}
/>
</RootPropsProvider>
)
})
export const PaginationEllipsis = React.forwardRef<
HTMLDivElement,
ChakraPagination.EllipsisProps
>(function PaginationEllipsis(props, ref) {
const { size, variantMap } = useRootProps()
return (
<ChakraPagination.Ellipsis ref={ref} {...props} asChild>
<Button as="span" variant={variantMap.ellipsis} size={size}>
<HiMiniEllipsisHorizontal />
</Button>
</ChakraPagination.Ellipsis>
)
})
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 (
<LinkButton href={getHref(props.value)} variant={variant} size={size}>
{props.value}
</LinkButton>
)
}
return (
<ChakraPagination.Item ref={ref} {...props} asChild>
<Button variant={variant} size={size}>
{props.value}
</Button>
</ChakraPagination.Item>
)
})
export const PaginationPrevTrigger = React.forwardRef<
HTMLButtonElement,
ChakraPagination.PrevTriggerProps
>(function PaginationPrevTrigger(props, ref) {
const { size, variantMap, getHref } = useRootProps()
const { previousPage } = usePaginationContext()
if (getHref) {
return (
<LinkButton
href={previousPage != null ? getHref(previousPage) : undefined}
variant={variantMap.default}
size={size}
>
<HiChevronLeft />
</LinkButton>
)
}
return (
<ChakraPagination.PrevTrigger ref={ref} asChild {...props}>
<IconButton variant={variantMap.default} size={size}>
<HiChevronLeft />
</IconButton>
</ChakraPagination.PrevTrigger>
)
})
export const PaginationNextTrigger = React.forwardRef<
HTMLButtonElement,
ChakraPagination.NextTriggerProps
>(function PaginationNextTrigger(props, ref) {
const { size, variantMap, getHref } = useRootProps()
const { nextPage } = usePaginationContext()
if (getHref) {
return (
<LinkButton
href={nextPage != null ? getHref(nextPage) : undefined}
variant={variantMap.default}
size={size}
>
<HiChevronRight />
</LinkButton>
)
}
return (
<ChakraPagination.NextTrigger ref={ref} asChild {...props}>
<IconButton variant={variantMap.default} size={size}>
<HiChevronRight />
</IconButton>
</ChakraPagination.NextTrigger>
)
})
export const PaginationItems = (props: React.HTMLAttributes<HTMLElement>) => {
return (
<ChakraPagination.Context>
{({ pages }) =>
pages.map((page, index) => {
return page.type === "ellipsis" ? (
<PaginationEllipsis key={index} index={index} {...props} />
) : (
<PaginationItem
key={index}
type="page"
value={page.value}
{...props}
/>
)
})
}
</ChakraPagination.Context>
)
}
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 (
<Text fontWeight="medium" ref={ref} {...rest}>
{content}
</Text>
)
})

View File

@@ -1,148 +0,0 @@
"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: <LuEye />, off: <LuEyeOff /> },
...rest
} = props
const [visible, setVisible] = useControllableState({
value: visibleProp,
defaultValue: defaultVisible || false,
onChange: onVisibleChange,
})
const inputRef = React.useRef<HTMLInputElement>(null)
return (
<InputGroup
width="full"
endElement={
<VisibilityTrigger
disabled={rest.disabled}
onPointerDown={(e) => {
if (rest.disabled) return
if (e.button !== 0) return
e.preventDefault()
setVisible(!visible)
}}
>
{visible ? visibilityIcon.off : visibilityIcon.on}
</VisibilityTrigger>
}
{...rootProps}
>
<Input
{...rest}
ref={mergeRefs(ref, inputRef)}
type={visible ? "text" : "password"}
/>
</InputGroup>
)
})
const VisibilityTrigger = React.forwardRef<HTMLButtonElement, ButtonProps>(
function VisibilityTrigger(props, ref) {
return (
<IconButton
tabIndex={-1}
ref={ref}
me="-2"
aspectRatio="square"
size="sm"
variant="ghost"
height="calc(100% - {spacing.2})"
aria-label="Toggle password visibility"
{...props}
/>
)
},
)
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 (
<Stack align="flex-end" gap="1" ref={ref} {...rest}>
<HStack width="full" ref={ref} {...rest}>
{Array.from({ length: max }).map((_, index) => (
<Box
key={index}
height="1"
flex="1"
rounded="sm"
data-selected={index < value ? "" : undefined}
layerStyle="fill.subtle"
colorPalette="gray"
_selected={{
colorPalette,
layerStyle: "fill.solid",
}}
/>
))}
</HStack>
{label && <HStack textStyle="xs">{label}</HStack>}
</Stack>
)
})
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" }
}
}

View File

@@ -1,27 +0,0 @@
import { PinInput as ChakraPinInput, Group } from "@chakra-ui/react"
import * as React from "react"
export interface PinInputProps extends ChakraPinInput.RootProps {
rootRef?: React.Ref<HTMLDivElement>
count?: number
inputProps?: React.InputHTMLAttributes<HTMLInputElement>
attached?: boolean
}
export const PinInput = React.forwardRef<HTMLInputElement, PinInputProps>(
function PinInput(props, ref) {
const { count = 4, inputProps, rootRef, attached, ...rest } = props
return (
<ChakraPinInput.Root ref={rootRef} {...rest}>
<ChakraPinInput.HiddenInput ref={ref} {...inputProps} />
<ChakraPinInput.Control>
<Group attached={attached}>
{Array.from({ length: count }).map((_, index) => (
<ChakraPinInput.Input key={index} index={index} />
))}
</Group>
</ChakraPinInput.Control>
</ChakraPinInput.Root>
)
},
)

View File

@@ -1,59 +0,0 @@
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<HTMLElement>
}
export const PopoverContent = React.forwardRef<
HTMLDivElement,
PopoverContentProps
>(function PopoverContent(props, ref) {
const { portalled = true, portalRef, ...rest } = props
return (
<Portal disabled={!portalled} container={portalRef}>
<ChakraPopover.Positioner>
<ChakraPopover.Content ref={ref} {...rest} />
</ChakraPopover.Positioner>
</Portal>
)
})
export const PopoverArrow = React.forwardRef<
HTMLDivElement,
ChakraPopover.ArrowProps
>(function PopoverArrow(props, ref) {
return (
<ChakraPopover.Arrow {...props} ref={ref}>
<ChakraPopover.ArrowTip />
</ChakraPopover.Arrow>
)
})
export const PopoverCloseTrigger = React.forwardRef<
HTMLButtonElement,
ChakraPopover.CloseTriggerProps
>(function PopoverCloseTrigger(props, ref) {
return (
<ChakraPopover.CloseTrigger
position="absolute"
top="1"
insetEnd="1"
{...props}
asChild
ref={ref}
>
<CloseButton size="sm" />
</ChakraPopover.CloseTrigger>
)
})
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

View File

@@ -1,37 +0,0 @@
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 (
<ChakraProgressCircle.Circle {...rest} ref={ref}>
<ChakraProgressCircle.Track stroke={trackColor} />
<ChakraProgressCircle.Range stroke={color} strokeLinecap={cap} />
</ChakraProgressCircle.Circle>
)
})
export const ProgressCircleValueText = React.forwardRef<
HTMLDivElement,
ChakraProgressCircle.ValueTextProps
>(function ProgressCircleValueText(props, ref) {
return (
<AbsoluteCenter>
<ChakraProgressCircle.ValueText {...props} ref={ref} />
</AbsoluteCenter>
)
})
export const ProgressCircleRoot = ChakraProgressCircle.Root

Some files were not shown because too many files have changed in this diff Show More