From 97044907ee1ef133f713c418fa01576c9e3aa3c9 Mon Sep 17 00:00:00 2001 From: Sonny Date: Sun, 28 Apr 2024 19:34:15 +0200 Subject: [PATCH] feat: create formlayout and create collection form --- inertia/components/common/form/_button.tsx | 27 ++++++++ inertia/components/common/form/_form.tsx | 10 +++ .../components/common/form/_form_field.tsx | 25 ++++++++ inertia/components/common/form/_input.tsx | 23 +++++++ inertia/components/common/form/textbox.tsx | 44 +++++++++++++ inertia/components/layouts/form_layout.tsx | 55 +++++++++++++++++ inertia/components/navbar/navbar.tsx | 41 ++++++++----- inertia/pages/app.tsx | 9 +++ inertia/pages/collection/create.tsx | 61 +++++++++++++++++++ inertia/pages/home.tsx | 21 +------ inertia/styles/reset.ts | 9 +-- inertia/styles/theme.ts | 34 ++++++++++- inertia/types/emotion.d.ts | 16 ++++- 13 files changed, 333 insertions(+), 42 deletions(-) create mode 100644 inertia/components/common/form/_button.tsx create mode 100644 inertia/components/common/form/_form.tsx create mode 100644 inertia/components/common/form/_form_field.tsx create mode 100644 inertia/components/common/form/_input.tsx create mode 100644 inertia/components/common/form/textbox.tsx create mode 100644 inertia/components/layouts/form_layout.tsx create mode 100644 inertia/pages/app.tsx create mode 100644 inertia/pages/collection/create.tsx diff --git a/inertia/components/common/form/_button.tsx b/inertia/components/common/form/_button.tsx new file mode 100644 index 0000000..1856016 --- /dev/null +++ b/inertia/components/common/form/_button.tsx @@ -0,0 +1,27 @@ +import styled from '@emotion/styled'; + +const Button = styled.button(({ theme }) => ({ + cursor: 'pointer', + width: '100%', + textTransform: 'uppercase', + fontSize: '14px', + color: theme.colors.white, + background: theme.colors.primary, + padding: '0.75em', + border: `1px solid ${theme.colors.primary}`, + borderRadius: theme.border.radius, + transition: theme.transition.delay, + + '&:disabled': { + cursor: 'not-allowed', + opacity: '0.75', + }, + + '&:not(:disabled):hover': { + boxShadow: `${theme.colors.darkBlue} 0 0 3px 1px`, + background: theme.colors.darkBlue, + color: theme.colors.white, + }, +})); + +export default Button; diff --git a/inertia/components/common/form/_form.tsx b/inertia/components/common/form/_form.tsx new file mode 100644 index 0000000..33fc5c8 --- /dev/null +++ b/inertia/components/common/form/_form.tsx @@ -0,0 +1,10 @@ +import styled from '@emotion/styled'; + +const Form = styled.form({ + width: '100%', + display: 'flex', + gap: '0.5em', + flexDirection: 'column', +}); + +export default Form; diff --git a/inertia/components/common/form/_form_field.tsx b/inertia/components/common/form/_form_field.tsx new file mode 100644 index 0000000..a6ec27e --- /dev/null +++ b/inertia/components/common/form/_form_field.tsx @@ -0,0 +1,25 @@ +import styled from '@emotion/styled'; + +const FormField = styled('div', { + shouldForwardProp: (propName) => propName !== 'required', +})<{ required?: boolean }>(({ required, theme }) => ({ + display: 'flex', + gap: '0.25em', + flexDirection: 'column', + + '& label': { + position: 'relative', + userSelect: 'none', + width: 'fit-content', + }, + + '& label::after': { + position: 'absolute', + top: 0, + right: '-0.75em', + color: theme.colors.red, + content: (required ? '"*"' : '""') as any, + }, +})); + +export default FormField; diff --git a/inertia/components/common/form/_input.tsx b/inertia/components/common/form/_input.tsx new file mode 100644 index 0000000..5771b32 --- /dev/null +++ b/inertia/components/common/form/_input.tsx @@ -0,0 +1,23 @@ +import styled from '@emotion/styled'; + +const Input = styled.input(({ theme }) => ({ + width: '100%', + color: theme.colors.font, + backgroundColor: theme.colors.white, + padding: '0.75em', + border: `1px solid ${theme.colors.lightestGrey}`, + borderBottom: `2px solid ${theme.colors.lightestGrey}`, + borderRadius: theme.border.radius, + transition: theme.transition.delay, + + '&:focus': { + borderBottom: `2px solid ${theme.colors.primary}`, + }, + + '&::placeholder': { + fontStyle: 'italic', + color: theme.colors.lightestGrey, + }, +})); + +export default Input; diff --git a/inertia/components/common/form/textbox.tsx b/inertia/components/common/form/textbox.tsx new file mode 100644 index 0000000..dd217c3 --- /dev/null +++ b/inertia/components/common/form/textbox.tsx @@ -0,0 +1,44 @@ +import { ChangeEvent, InputHTMLAttributes, useState } from 'react'; +import FormField from '~/components/common/form/_form_field'; +import Input from '~/components/common/form/_input'; + +interface InputProps + extends Omit, 'onChange'> { + label: string; + name: string; + value?: string; + onChange?: (name: string, value: string) => void; +} + +export default function TextBox({ + name, + label, + value = '', + onChange, + required = false, + ...props +}: InputProps): JSX.Element { + const [inputValue, setInputValue] = useState(value); + + function _onChange({ target }: ChangeEvent) { + setInputValue(target.value); + if (onChange) { + onChange(target.name, target.value); + } + } + + return ( + + + + + ); +} diff --git a/inertia/components/layouts/form_layout.tsx b/inertia/components/layouts/form_layout.tsx new file mode 100644 index 0000000..2478913 --- /dev/null +++ b/inertia/components/layouts/form_layout.tsx @@ -0,0 +1,55 @@ +import PATHS from '#constants/paths'; +import styled from '@emotion/styled'; +import { Link } from '@inertiajs/react'; +import { FormEvent, ReactNode } from 'react'; +import Button from '~/components/common/form/_button'; +import Form from '~/components/common/form/_form'; +import BaseLayout from './_base_layout'; + +const FormLayoutStyle = styled.div(({ theme }) => ({ + height: 'fit-content', + width: theme.media.mobile, + maxWidth: '100%', + marginTop: '10em', + display: 'flex', + gap: '0.75em', + flexDirection: 'column', +})); + +interface FormLayoutProps { + title: string; + children: ReactNode; + + canSubmit: boolean; + handleSubmit: (event: FormEvent) => void; + textSubmitButton?: string; + + disableHomeLink?: boolean; +} + +const FormLayout = ({ + title, + children, + canSubmit, + handleSubmit, + textSubmitButton = 'Confirm', + disableHomeLink = false, +}: FormLayoutProps) => ( + + +

{title}

+
+ {children} + +
+ {!disableHomeLink && ( + // {t('common:back-home')} + ← Revenir à l'accueil + )} +
+
+); + +export default FormLayout; diff --git a/inertia/components/navbar/navbar.tsx b/inertia/components/navbar/navbar.tsx index 719fe84..dcf563a 100644 --- a/inertia/components/navbar/navbar.tsx +++ b/inertia/components/navbar/navbar.tsx @@ -17,13 +17,15 @@ const Nav = styled.nav({ alignItems: 'center', }); -const NavList = styled(UnstyledList)(({ theme, right }) => ({ - display: 'flex', - flex: 1, - gap: '1.5em', - justifyContent: right ? 'flex-end' : 'flex-start', - transition: theme.transition.delay, -})); +const NavList = styled(UnstyledList)( + ({ theme, right }) => ({ + display: 'flex', + flex: 1, + gap: '1.5em', + justifyContent: right ? 'flex-end' : 'flex-start', + transition: theme.transition.delay, + }) +); const UserCard = styled.div({ display: 'flex', @@ -53,14 +55,23 @@ export default function Navbar() { GitHub {isAuthenticated && !!user ? ( -
  • - - - - {user.nickName} - - -
  • + <> +
  • + Dashboard +
  • +
  • + + + + {user.nickName} + + +
  • + ) : (
  • Login diff --git a/inertia/pages/app.tsx b/inertia/pages/app.tsx new file mode 100644 index 0000000..021e2a5 --- /dev/null +++ b/inertia/pages/app.tsx @@ -0,0 +1,9 @@ +import { Link } from '@inertiajs/react'; + +export default function AppPage() { + return ( +
    + Add collection +
    + ); +} diff --git a/inertia/pages/collection/create.tsx b/inertia/pages/collection/create.tsx new file mode 100644 index 0000000..440c6aa --- /dev/null +++ b/inertia/pages/collection/create.tsx @@ -0,0 +1,61 @@ +import { useForm } from '@inertiajs/react'; +import { ChangeEvent, FormEvent, useMemo } from 'react'; +import FormField from '~/components/common/form/_form_field'; +import TextBox from '~/components/common/form/textbox'; +import FormLayout from '~/components/layouts/form_layout'; +import { Visibility } from '../../../app/enums/visibility'; + +export default function CreateCollectionPage() { + const { data, setData, post, processing, errors } = useForm({ + name: '', + description: '', + visibility: Visibility.PRIVATE, + }); + const isFormDisabled = useMemo( + () => processing || data.name.length === 0, + [processing, data] + ); + + function handleOnCheck({ target }: ChangeEvent) { + setData( + 'visibility', + target.checked ? Visibility.PUBLIC : Visibility.PRIVATE + ); + } + + function handleSubmit(e: FormEvent) { + e.preventDefault(); + post('/collections'); + } + + return ( + + + {errors.name &&
    {errors.name}
    } + + {errors.description &&
    {errors.description}
    } + + + + +
    + ); +} diff --git a/inertia/pages/home.tsx b/inertia/pages/home.tsx index 93acd28..13036f4 100644 --- a/inertia/pages/home.tsx +++ b/inertia/pages/home.tsx @@ -1,24 +1,7 @@ -import { InferPageProps } from '@adonisjs/inertia/types'; +import type { InferPageProps } from '@adonisjs/inertia/types'; import ContentLayout from '~/components/layouts/content_layout'; -import useUser from '~/hooks/use_user'; import type AppsController from '../../app/controllers/apps_controller'; export default function Home(_: InferPageProps) { - const { isAuthenticated, user } = useUser(); - - return ( - -
    -
    AdonisJS x Inertia x React
    - - - Learn more about AdonisJS and Inertia.js by visiting the{' '} - AdonisJS documentation. - - - {isAuthenticated ? 'Authenticated' : 'Not authenticated'} -
    {JSON.stringify(user, null, 2)}
    -
    -
    - ); + return blablabla welcome to MyLinks; } diff --git a/inertia/styles/reset.ts b/inertia/styles/reset.ts index 10c103c..ed2dd19 100644 --- a/inertia/styles/reset.ts +++ b/inertia/styles/reset.ts @@ -1,4 +1,5 @@ import { css } from '@emotion/react'; +import { theme } from '~/styles/theme'; export const cssReset = css({ '*': { @@ -17,20 +18,20 @@ export const cssReset = css({ border: 0, }, - 'a': { + a: { width: 'fit-content', color: '#3f88c5', textDecoration: 'none', borderBottom: '1px solid transparent', }, - 'b': { + b: { fontWeight: 600, letterSpacing: '0.5px', }, 'h1, h2, h3, h4, h5, h6': { - fontWeight: '400', - margin: '1em 0', + fontWeight: '500', + color: theme.colors.primary, }, }); diff --git a/inertia/styles/theme.ts b/inertia/styles/theme.ts index e77e537..9bba33a 100644 --- a/inertia/styles/theme.ts +++ b/inertia/styles/theme.ts @@ -5,14 +5,28 @@ const black = '#333'; const darkBlack = '#111'; const white = '#fff'; -const gray = '#7c7c7c'; +const lightestGrey = '#dadce0'; +const lightGrey = '#f0eef6'; +const grey = '#aaa'; +const darkGrey = '#4b5563'; + +const lightestBlue = '#d3e8fa'; +const lightBlue = '#82c5fede'; const blue = '#3f88c5'; +const darkBlue = '#005aa5'; +const darkestBlue = '#1f2937'; + +const lightRed = '#ffbabab9'; +const red = '#d8000c'; + +const lightGreen = '#c1ffbab9'; +const green = 'green'; export const theme: Theme = { colors: { font: black, - background: white, + background: lightGrey, primary: blue, lightBlack, @@ -20,9 +34,23 @@ export const theme: Theme = { darkBlack, white, - gray, + lightestGrey, + lightGrey, + grey, + darkGrey, + + lightestBlue, + lightBlue, blue, + darkBlue, + darkestBlue, + + lightRed, + red, + + lightGreen, + green, }, border: { diff --git a/inertia/types/emotion.d.ts b/inertia/types/emotion.d.ts index 006ccee..ac7167b 100644 --- a/inertia/types/emotion.d.ts +++ b/inertia/types/emotion.d.ts @@ -12,9 +12,23 @@ declare module '@emotion/react' { darkBlack: string; white: string; - gray: string; + lightestGrey: string; + lightGrey: string; + grey: string; + darkGrey: string; + + lightestBlue: string; + lightBlue: string; blue: string; + darkBlue: string; + darkestBlue: string; + + lightRed: string; + red: string; + + lightGreen: string; + green: string; }; border: {