Skip to content

Commit

Permalink
Improve UX in forms (Fix #1)
Browse files Browse the repository at this point in the history
  • Loading branch information
AntonioVdlC committed Feb 17, 2022
1 parent d63bf55 commit 35fc3dc
Show file tree
Hide file tree
Showing 12 changed files with 118 additions and 110 deletions.
20 changes: 20 additions & 0 deletions app/assets/tail-spin.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
17 changes: 13 additions & 4 deletions app/components/Button.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,11 +2,14 @@ import { Link } from "remix";

import type { ButtonHTMLAttributes, HTMLAttributes, ReactChild } from "react";

import spinIcon from "~/assets/tail-spin.svg";

type Props = {
children: ReactChild | ReactChild[];
primary?: boolean;
secondary?: boolean;
external?: boolean;
loading?: boolean;
to?: string;
};

Expand All @@ -15,6 +18,7 @@ export default function Button({
primary = false,
secondary = false,
external = false,
loading = false,
to,
...props
}: Props &
Expand All @@ -23,14 +27,14 @@ export default function Button({
let color;
if (primary) {
color =
"bg-slate-600 text-white font-medium hover:bg-slate-700 focus:ring-slate-800";
"bg-slate-600 text-white font-medium hover:bg-slate-700 focus:ring-slate-800 disabled:opacity-50 disabled:cursor-progress disabled:hover:bg-slate-600";
}
if (secondary) {
color =
"bg-slate-100 text-slate-800 font-medium hover:bg-slate-200 focus:ring-slate-300";
"bg-slate-100 text-slate-800 font-medium hover:bg-slate-200 focus:ring-slate-300 disabled:opacity-50 disabled:cursor-progress disabled:hover:bg-slate-100";
}

const className = `block text-center whitespace-nowrap w-full py-3 px-4 rounded-md shadow focus:outline-none focus:ring-2 focus:ring-inset ${color}`;
const className = `relative block text-center whitespace-nowrap w-full py-3 px-4 rounded-md shadow focus:outline-none focus:ring-2 focus:ring-inset ${color}`;

return to ? (
external ? (
Expand All @@ -49,7 +53,12 @@ export default function Button({
</Link>
)
) : (
<button {...props} className={className}>
<button {...props} className={className} disabled={loading}>
{loading ? (
<span className="absolute left-4 motion-reduce:hidden">
<img className="h-6 w-6" src={spinIcon} />
</span>
) : null}{" "}
{children}
</button>
);
Expand Down
8 changes: 5 additions & 3 deletions app/components/ErrorPage.tsx
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import { Link } from "remix";

import Logo from "~/components/Logo";
import classNames from "~/utils/class-names";

type Props = {
status: number;
Expand All @@ -23,9 +24,10 @@ export default function ErrorPage({
<div className="flex min-h-full flex-col bg-slate-50 pt-16 pb-12">
<main className="mx-auto flex w-full max-w-7xl flex-grow flex-col justify-center px-4 sm:px-6 lg:px-8">
<div
className={`flex flex-shrink-0 justify-center ${
status === 404 ? "animate-pulse" : ""
}`}
className={classNames(
"flex flex-shrink-0 justify-center",
status === 404 ? "motion-safe:animate-pulse" : ""
)}
>
<Logo size="lg" withLink />
</div>
Expand Down
2 changes: 1 addition & 1 deletion app/components/Loading.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ type Props = {
export default function Loading({ text }: Props) {
return (
<>
<div className="animate-ping">
<div className="motion-safe:animate-ping">
<Logo size="md" />
</div>
{text ? <p className="mt-12 text-slate-900">{text}</p> : null}
Expand Down
8 changes: 5 additions & 3 deletions app/components/WebsiteCreateForm.tsx
Original file line number Diff line number Diff line change
@@ -1,10 +1,12 @@
import { Form } from "remix";
import { Form, useTransition } from "remix";

import Button from "~/components/Button";
import Input from "~/components/Input";
import LayoutGrid from "~/components/LayoutGrid";

export default function WebsiteCreateForm() {
const transition = useTransition();

return (
<Form
method="post"
Expand All @@ -29,8 +31,8 @@ export default function WebsiteCreateForm() {
/>
</LayoutGrid>
<LayoutGrid>
<Button primary type="submit">
Add website
<Button primary type="submit" loading={Boolean(transition.submission)}>
{transition.submission ? "Creating ..." : "Add website"}
</Button>
</LayoutGrid>
</Form>
Expand Down
11 changes: 8 additions & 3 deletions app/routes/app/user.tsx
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { Form, json, useLoaderData } from "remix";
import { Form, json, useLoaderData, useTransition } from "remix";

import type { ActionFunction, LoaderFunction } from "remix";
import type { User } from "@prisma/client";
Expand Down Expand Up @@ -84,6 +84,7 @@ export const action: ActionFunction = async ({ request }) => {

export default function AppUserRoute() {
const data = useLoaderData<LoaderData>();
const transition = useTransition();

return (
<>
Expand Down Expand Up @@ -125,8 +126,12 @@ export default function AppUserRoute() {
<div className="mt-3"></div>

<LayoutGrid>
<Button type="submit" primary>
Update
<Button
type="submit"
primary
loading={Boolean(transition.submission)}
>
{transition.submission ? "Updating ..." : "Update"}
</Button>
</LayoutGrid>
</Form>
Expand Down
21 changes: 14 additions & 7 deletions app/routes/app/websites.details.$id.tsx
Original file line number Diff line number Diff line change
@@ -1,13 +1,14 @@
import { useState } from "react";
import { useLoaderData, Link, ActionFunction } from "remix";
import { useLoaderData, Link, Form, useTransition } from "remix";
import {
ExternalLinkIcon,
ClipboardCopyIcon,
ClipboardCheckIcon,
} from "@heroicons/react/outline";
import { Role } from "@prisma/client";

import type { LoaderFunction } from "remix";
import { Org, Role, User, UserOrg, Website } from "@prisma/client";
import type { LoaderFunction, ActionFunction } from "remix";
import type { Org, User, UserOrg, Website } from "@prisma/client";

import classNames from "~/utils/class-names";
import { db } from "~/utils/db.server";
Expand Down Expand Up @@ -77,6 +78,8 @@ export default function WebsiteDetailsRoute() {
});
}

const transition = useTransition();

return (
<>
<div>
Expand Down Expand Up @@ -174,7 +177,7 @@ export default function WebsiteDetailsRoute() {

<H2>Website Settings</H2>
<div className="mt-5">
<form method="post">
<Form method="post">
<div className="relative flex items-start">
<div className="flex h-5 items-center">
<input
Expand Down Expand Up @@ -204,12 +207,16 @@ export default function WebsiteDetailsRoute() {

<div className="mt-5">
<LayoutGrid>
<Button type="submit" primary>
Update Settings
<Button
type="submit"
primary
loading={Boolean(transition.submission)}
>
{transition.submission ? "Updating ..." : "Update Settings"}
</Button>
</LayoutGrid>
</div>
</form>
</Form>
</div>
</>
);
Expand Down
9 changes: 8 additions & 1 deletion app/routes/auth/login.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import {
redirect,
useActionData,
useSearchParams,
useTransition,
} from "remix";

import type { ActionFunction, LoaderFunction } from "remix";
Expand Down Expand Up @@ -110,6 +111,8 @@ export const action: ActionFunction = async ({ request }) => {
export default function Login() {
const actionData = useActionData<ActionData>();
const [searchParams] = useSearchParams();
const transition = useTransition();

return (
<div className="w-screen">
<div className="bg-slate-50 pt-10 sm:pt-16 lg:overflow-hidden lg:pt-8 lg:pb-14">
Expand Down Expand Up @@ -179,7 +182,11 @@ export default function Login() {
</div>
</div>

<Button primary type="submit">
<Button
primary
type="submit"
loading={Boolean(transition.submission)}
>
Submit
</Button>
</Form>
Expand Down
2 changes: 1 addition & 1 deletion app/routes/auth/logout.callback.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ import Logo from "~/components/Logo";
export default function LogoutCallbackRouter() {
return (
<>
<div className="flex animate-pulse justify-center">
<div className="flex justify-center motion-safe:animate-pulse">
<Logo size="lg" withLink />
</div>

Expand Down
2 changes: 1 addition & 1 deletion app/routes/auth/waitlist.sent.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ export default function LoginSentRoute() {

return (
<>
<div className="flex animate-bounce justify-center">
<div className="flex justify-center motion-safe:animate-bounce">
<Logo size="lg" withLink />
</div>
<div className="mt-6 px-4 text-center md:w-1/2">
Expand Down
20 changes: 17 additions & 3 deletions app/routes/auth/waitlist.tsx
Original file line number Diff line number Diff line change
@@ -1,4 +1,11 @@
import { Form, useActionData, redirect, json, Link } from "remix";
import {
Form,
useActionData,
redirect,
json,
Link,
useTransition,
} from "remix";

import type { ActionFunction, LoaderFunction } from "remix";

Expand Down Expand Up @@ -79,6 +86,7 @@ export const action: ActionFunction = async ({ request }) => {

export default function RegisterRoute() {
const actionData = useActionData<ActionData>();
const transition = useTransition();

return (
<div className="w-screen">
Expand Down Expand Up @@ -140,8 +148,14 @@ export default function RegisterRoute() {
</div>
</div>

<Button primary type="submit">
Join the waitlist
<Button
primary
type="submit"
loading={Boolean(transition.submission)}
>
{transition.submission
? "Joining ..."
: "Join the waitlist"}
</Button>
</Form>

Expand Down
Loading

0 comments on commit 35fc3dc

Please sign in to comment.