Skip to content

Commit

Permalink
Merge pull request mantinedev#11 from widgeter/new-components
Browse files Browse the repository at this point in the history
Include a Contact page
  • Loading branch information
prototypa authored Mar 8, 2023
2 parents a66e3d9 + 696f1b9 commit f1dbac9
Show file tree
Hide file tree
Showing 11 changed files with 446 additions and 146 deletions.
14 changes: 14 additions & 0 deletions app/contact/page.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
import Contact2 from '~/components/widgets/Contact2';
import Features2 from '~/components/widgets/Features2';
import { featuresData1 } from '~/shared/data';

const Page = () => {
return (
<>
<Contact2 />
<Features2 {...featuresData1} />
</>
);
};

export default Page;
4 changes: 2 additions & 2 deletions app/page.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -8,15 +8,15 @@ import FAQs2 from '~/components/widgets/FAQs2';
import Pricing from '~/components/widgets/Pricing';
import Team from '~/components/widgets/Team';
import CallToAction2 from '~/components/widgets/CallToAction2';
import { content2Data, contentData } from '~/shared/data';
import { content2Data, contentData, featuresData } from '~/shared/data';
import Contact from '~/components/widgets/Contact';

export default function Page() {
return (
<>
<Hero />
<SocialProof />
<Features3 />
<Features3 {...featuresData} />
<Content {...contentData} />
<Content {...content2Data} />
<Steps />
Expand Down
135 changes: 135 additions & 0 deletions src/components/common/Form.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,135 @@
'use client';

import { useState } from 'react';
import { FormProps } from '../../shared/types';

const Form = ({ title, description, inputs, radioBtns, textarea, checkboxes, btn, btnPosition }: FormProps) => {
const [inputValues, setInputValues] = useState([]);
const [radioBtnValue, setRadioBtnValue] = useState('');
const [textareaValues, setTextareaValues] = useState('');
const [checkedState, setCheckedState] = useState<boolean[]>(new Array(checkboxes && checkboxes.length).fill(false));

// Update the value of the entry fields
const changeInputValueHandler = (event: React.ChangeEvent<HTMLInputElement>) => {
const { name, value } = event.target;

setInputValues({
...inputValues,
[name]: value,
});
};

// Update checked radio buttons
const changeRadioBtnsHandler = (event: React.ChangeEvent<HTMLInputElement>) => {
setRadioBtnValue(event.target.value);
};

// Update the textarea value
const changeTextareaHandler = (event: React.ChangeEvent<HTMLTextAreaElement>) => {
setTextareaValues(event.target.value);
};

// Update checkbox radio buttons
const changeCheckboxHandler = (index: number) => {
setCheckedState((prevValues) => {
const newValues = [...(prevValues as boolean[])];
newValues.map(() => {
newValues[index] = !checkedState[index];
});
return newValues;
});
};

return (
<div className="card h-fit max-w-6xl p-5 md:p-12" id="form">
{title && <h2 className={`${description ? 'mb-2' : 'mb-4'} text-2xl font-bold`}>{title}</h2>}
{description && <p className="mb-4">{description}</p>}
<form id="contactForm">
<div className="mb-6">
{/* Inputs */}
<div className="mx-0 mb-1 sm:mb-4">
{inputs.map(({ type, label, name, placeholder }, index) => (
<div key={`item-input-${index}`} className="mx-0 mb-1 sm:mb-4">
<label htmlFor={name} className="pb-1 text-xs uppercase tracking-wider">
{label}
</label>
<input
type={type}
name={name}
value={inputValues[index]}
onChange={changeInputValueHandler}
placeholder={placeholder}
className="mb-2 w-full rounded-md border border-gray-400 py-2 pl-2 pr-4 shadow-md dark:text-gray-300 sm:mb-0"
/>
</div>
))}
</div>
{/* Radio buttons */}
{radioBtns && (
<div className="mx-0 mb-1 sm:mb-3">
<label className="pb-1 text-xs uppercase tracking-wider">{radioBtns?.label}</label>
<div className="flex flex-wrap">
{radioBtns.radios.map(({ label }, index) => (
<div key={`radio-btn-${index}`} className="mr-4 items-baseline">
<input
type="radio"
name={label}
value={`value${index}`}
checked={radioBtnValue === `value${index}`}
onChange={changeRadioBtnsHandler}
className="cursor-pointer"
/>
<label className="ml-2">{label}</label>
</div>
))}
</div>
</div>
)}
{/* Textarea */}
{textarea && (
<div className={`mx-0 mb-1 sm:mb-4`}>
<label htmlFor={textarea.name} className="pb-1 text-xs uppercase tracking-wider">
{textarea.label}
</label>
<textarea
name={textarea.name}
cols={textarea.cols}
rows={textarea.rows}
value={textareaValues}
onChange={(e) => changeTextareaHandler(e)}
placeholder={textarea.placeholder}
className="mb-2 w-full rounded-md border border-gray-400 py-2 pl-2 pr-4 shadow-md dark:text-gray-300 sm:mb-0"
/>
</div>
)}
{/* Checkboxes */}
{checkboxes && (
<div className="mx-0 mb-1 sm:mb-4">
{checkboxes.map(({ label }, index) => (
<div key={`checkbox-${index}`} className="mx-0 my-1 flex items-baseline">
<input
type="checkbox"
name={label}
checked={checkedState[index]}
onChange={() => changeCheckboxHandler(index)}
className="cursor-pointer"
/>
<label className="ml-2">{label}</label>
</div>
))}
</div>
)}
</div>
<div
className={`${btnPosition === 'left' ? 'text-left' : btnPosition === 'right' ? 'text-right' : 'text-center'}`}
>
<button type={btn.type} className="btn btn-primary sm:mb-0">
{btn.title}
</button>
</div>
</form>
</div>
);
};

export default Form;
38 changes: 3 additions & 35 deletions src/components/widgets/Contact.tsx
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import { contactData } from '~/shared/data';
import Form from '../common/Form';
import HeaderWidget from '../common/HeaderWidget';

const Contact = () => {
Expand All @@ -9,7 +10,7 @@ const Contact = () => {
<div className="mx-auto max-w-6xl px-4 py-16 sm:px-6 lg:px-8 lg:py-20">
{header && <HeaderWidget header={header} titleClassname="text-3xl sm:text-5xl" />}
<div className="flex items-stretch justify-center">
<div className="grid md:grid-cols-2 md:items-center">
<div className="grid md:grid-cols-2">
<div className="h-full pr-6">
{content && <p className="mt-3 mb-12 text-lg text-gray-600 dark:text-slate-400">{content}</p>}
<ul className="mb-6 md:mb-0">
Expand Down Expand Up @@ -37,40 +38,7 @@ const Contact = () => {
))}
</ul>
</div>
<div className="card h-full p-5 md:p-8">
<h2 className="text-2xl font-bold">{form.title}</h2>
<p>{form.description}</p>
<form id="contactForm" className="mt-4">
<div className="mb-4">
<div className="my-1 grid grid-cols-1 md:my-0">
{form.inputs.map(({ type, name, placeholder }, index) => (
<div key={`item-input-${index}`} className="my-1 mx-0">
<input
type={type}
name={name}
placeholder={placeholder}
className="w-full rounded-md border border-gray-400 py-2 pl-2 pr-4 shadow-md dark:text-gray-300"
/>
<div className="invalid-feedback" style={{ display: 'block' }}></div>
</div>
))}
<div className="mx-0 my-1">
<textarea
name="text"
cols={30}
rows={5}
placeholder="Write your message..."
className="w-full rounded-md border border-gray-400 py-2 pl-2 pr-4 shadow-md dark:text-gray-300"
></textarea>
<div className="invalid-feedback" style={{ display: 'block' }}></div>
</div>
</div>
</div>
<button type={form.btn.type} className="btn btn-primary sm:mb-0">
{form.btn.title}
</button>
</form>
</div>
<Form {...form} btnPosition="center" />
</div>
</div>
</div>
Expand Down
20 changes: 20 additions & 0 deletions src/components/widgets/Contact2.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
import { contact2Data } from '~/shared/data';
import Form from '../common/Form';
import HeaderWidget from '../common/HeaderWidget';

const Contact2 = () => {
const { header, form } = contact2Data;

return (
<section className="bg-primary-50 dark:bg-slate-800" id="contactTwo">
<div className="mx-auto max-w-6xl px-4 py-16 sm:px-6 lg:px-8 lg:py-20">
{header && <HeaderWidget header={header} titleClassname="text-3xl sm:text-5xl" />}
<div className="flex items-stretch justify-center">
<Form {...form} btnPosition="right" />
</div>
</div>
</section>
);
};

export default Contact2;
3 changes: 1 addition & 2 deletions src/components/widgets/Content.tsx
Original file line number Diff line number Diff line change
@@ -1,11 +1,10 @@
import { FC } from 'react';
import Image from 'next/image';
import { IconCheck } from '@tabler/icons-react';

import { ContentProps } from '~/shared/types';
import HeaderWidget from '../common/HeaderWidget';

const Content: FC<ContentProps> = ({ header, content, items, image, isReversed, isAfterContent }) => (
const Content = ({ header, content, items, image, isReversed, isAfterContent }: ContentProps) => (
<section className="bg-primary-50 dark:bg-slate-800">
<div
className={`mx-auto max-w-6xl px-4 sm:px-6 lg:px-8 ${isAfterContent ? 'pt-1 pb-16 md:pb-20' : 'py-16 md:py-20'}`}
Expand Down
46 changes: 21 additions & 25 deletions src/components/widgets/Features.tsx
Original file line number Diff line number Diff line change
@@ -1,33 +1,29 @@
import { featuresData } from '~/shared/data';
import { FeaturesProps } from '~/shared/types';
import HeaderWidget from '../common/HeaderWidget';

const Features = () => {
const { header, items } = featuresData;

return (
<section className="scroll-mt-16" id="features">
<div className="mx-auto max-w-6xl px-4 py-16 lg:px-8 lg:py-20">
{header && <HeaderWidget header={header} titleClassname="text-4xl md:text-5xl" />}
<div className="mx-auto grid space-y-6 md:grid-cols-2 md:space-y-0">
{items.map(({ title, description, icon: Icon }, index) => (
<div key={`item-feature-${index}`} className="space-y-8 sm:px-8">
<div className="flex md:max-w-md">
<div className="mb-4 mr-4">
<div className="flex h-12 w-12 items-center justify-center rounded-full bg-primary-500 dark:bg-primary-700">
{Icon && <Icon className="icon-light h-6 w-6 text-white" />}
</div>
</div>
<div className="mb-0 md:mb-8">
<h3 className="mb-3 text-xl font-bold">{title}</h3>
<p className="text-gray-600 dark:text-slate-400">{description}</p>
const Features = ({ header, items }: FeaturesProps) => (
<section className="scroll-mt-16" id="features">
<div className="mx-auto max-w-6xl px-4 py-16 lg:px-8 lg:py-20">
{header && <HeaderWidget header={header} titleClassname="text-4xl md:text-5xl" />}
<div className="mx-auto grid space-y-6 md:grid-cols-2 md:space-y-0">
{items.map(({ title, description, icon: Icon }, index) => (
<div key={`item-feature-${index}`} className="space-y-8 sm:px-8">
<div className="flex md:max-w-md">
<div className="mb-4 mr-4">
<div className="flex h-12 w-12 items-center justify-center rounded-full bg-primary-500 dark:bg-primary-700">
{Icon && <Icon className="icon-light h-6 w-6 text-white" />}
</div>
</div>
<div className="mb-0 md:mb-8">
<h3 className="mb-3 text-xl font-bold">{title}</h3>
<p className="text-gray-600 dark:text-slate-400">{description}</p>
</div>
</div>
))}
</div>
</div>
))}
</div>
</section>
);
};
</div>
</section>
);

export default Features;
63 changes: 38 additions & 25 deletions src/components/widgets/Features2.tsx
Original file line number Diff line number Diff line change
@@ -1,31 +1,44 @@
import { featuresData } from '~/shared/data';
import { Fragment } from 'react';
import { FeaturesProps } from '~/shared/types';
import HeaderWidget from '../common/HeaderWidget';

const Features2 = () => {
const { header, items } = featuresData;

return (
<section className="relative py-16 lg:py-20" id="features2">
<div className="pointer-events-none absolute inset-0 mb-36 bg-primary-50 dark:bg-slate-800"></div>
<div className="relative mx-auto -mb-12 max-w-6xl px-4 sm:px-6">
{header && <HeaderWidget header={header} titleClassname="text-4xl md:text-5xl" />}
<div className={`my-12 grid items-stretch gap-6 dark:text-white sm:grid-cols-1 md:grid-cols-2 lg:grid-cols-3`}>
{items.map(({ title, description, icon: Icon }, index) => (
<div
key={`item-feature2-${index}`}
className="relative flex flex-col rounded border border-transparent bg-white p-6 shadow-lg transition hover:shadow-md dark:border-slate-800 dark:bg-slate-900"
>
<div className="flex items-center">
{Icon && <Icon className="h-10 w-10" />}
<div className="ml-4 text-xl font-bold">{title}</div>
const Features2 = ({ header, items }: FeaturesProps) => (
<section className="relative py-16 lg:py-20" id="features2">
<div className="pointer-events-none absolute inset-0 mb-36 bg-primary-50 dark:bg-slate-800"></div>
<div className="relative mx-auto -mb-12 max-w-6xl px-4 sm:px-6">
{header && <HeaderWidget header={header} titleClassname="text-4xl md:text-5xl" />}
<div
className={`my-12 ${
items.length > 2 ? 'grid sm:grid-cols-1 md:grid-cols-2 lg:grid-cols-3' : 'flex justify-center'
} items-stretch gap-6`}
>
{items.map(({ title, description, icon: Icon, link }, index) => (
<Fragment key={`item-feature2-${index}`}>
{link ? (
<a
href={link.href}
className="relative flex min-w-[22em] flex-col rounded border border-transparent bg-white p-6 shadow-lg transition hover:shadow-md dark:border-slate-800 dark:bg-slate-900 dark:text-white dark:shadow-[0_4px_10px_4px_rgba(30,41,59,0.3)]"
>
<div className="flex items-center">
{Icon && <Icon className="h-10 w-10" />}
<div className="ml-4 text-xl font-bold">{title}</div>
</div>
{description && <p className="text-md mt-4 text-gray-500 dark:text-gray-400">{description}</p>}
</a>
) : (
<div className="relative flex min-w-[22em] flex-col rounded border border-transparent bg-white p-6 shadow-lg transition hover:shadow-md dark:border-slate-800 dark:bg-slate-900">
<div className="flex items-center">
{Icon && <Icon className="h-10 w-10" />}
<div className="ml-4 text-xl font-bold">{title}</div>
</div>
{description && <p className="text-md mt-4 text-gray-500 dark:text-gray-400">{description}</p>}
</div>
{description && <p className="text-md mt-4 text-gray-500 dark:text-gray-400">{description}</p>}
</div>
))}
</div>
)}
</Fragment>
))}
</div>
</section>
);
};
</div>
</section>
);

export default Features2;
Loading

0 comments on commit f1dbac9

Please sign in to comment.