chore: loading spinner accessibilities

pull/3813/head
Arik Chakma 2 years ago
parent 11d7618230
commit 05c9bbec8b
  1. 8
      src/components/Login/EmailLoginForm.tsx
  2. 3
      src/components/Login/EmailSignupForm.tsx
  3. 25
      src/components/Profile/ForgotPasswordForm.tsx
  4. 25
      src/components/Profile/ResetPasswordForm.tsx
  5. 25
      src/components/Setting/ChangePasswordForm.tsx
  6. 25
      src/components/Setting/UpdateProfileForm.tsx
  7. 42
      src/components/Spinner.astro
  8. 26
      src/components/Spinner.tsx

@ -2,6 +2,7 @@ import Cookies from 'js-cookie';
import type { FunctionComponent } from 'preact'; import type { FunctionComponent } from 'preact';
import { useState } from 'preact/hooks'; import { useState } from 'preact/hooks';
import { TOKEN_COOKIE_NAME } from '../../lib/constants'; import { TOKEN_COOKIE_NAME } from '../../lib/constants';
import Spinner from '../Spinner';
const EmailLoginForm: FunctionComponent<{}> = () => { const EmailLoginForm: FunctionComponent<{}> = () => {
const [email, setEmail] = useState<string>(''); const [email, setEmail] = useState<string>('');
@ -45,6 +46,11 @@ const EmailLoginForm: FunctionComponent<{}> = () => {
password, password,
}), }),
}); });
// TODO: Remove this on production
// Simulate slow network - 2 seconds
// await new Promise((resolve) => setTimeout(resolve, 2000));
const json = await res.json(); const json = await res.json();
// If the response isn't ok, we'll throw an error // If the response isn't ok, we'll throw an error
@ -195,7 +201,7 @@ const EmailLoginForm: FunctionComponent<{}> = () => {
type="submit" type="submit"
className="mt-3 inline-flex h-10 w-full items-center justify-center rounded-lg border border-slate-300 bg-black p-2 text-sm font-medium text-white outline-none transition duration-150 ease-in-out focus:ring-2 focus:ring-black focus:ring-offset-1 disabled:opacity-60" className="mt-3 inline-flex h-10 w-full items-center justify-center rounded-lg border border-slate-300 bg-black p-2 text-sm font-medium text-white outline-none transition duration-150 ease-in-out focus:ring-2 focus:ring-black focus:ring-offset-1 disabled:opacity-60"
> >
Continue {isLoading ? <Spinner className="text-white" /> : 'Continue'}
</button> </button>
</form> </form>
); );

@ -2,6 +2,7 @@ import Cookies from 'js-cookie';
import type { FunctionComponent } from 'preact'; import type { FunctionComponent } from 'preact';
import { useState } from 'preact/hooks'; import { useState } from 'preact/hooks';
import { TOKEN_COOKIE_NAME } from '../../lib/constants'; import { TOKEN_COOKIE_NAME } from '../../lib/constants';
import Spinner from '../Spinner';
const EmailSignupForm: FunctionComponent<{}> = () => { const EmailSignupForm: FunctionComponent<{}> = () => {
const [email, setEmail] = useState<string>(''); const [email, setEmail] = useState<string>('');
@ -125,7 +126,7 @@ const EmailSignupForm: FunctionComponent<{}> = () => {
} }
className="mt-3 inline-flex h-10 w-full items-center justify-center rounded-lg border border-slate-300 bg-black p-2 text-sm font-medium text-white outline-none transition duration-150 ease-in-out focus:ring-2 focus:ring-black focus:ring-offset-1 disabled:opacity-60" className="mt-3 inline-flex h-10 w-full items-center justify-center rounded-lg border border-slate-300 bg-black p-2 text-sm font-medium text-white outline-none transition duration-150 ease-in-out focus:ring-2 focus:ring-black focus:ring-offset-1 disabled:opacity-60"
> >
Continue {isLoading ? <Spinner className="text-white" /> : 'Continue'}
</button> </button>
</form> </form>
); );

@ -1,4 +1,5 @@
import { useState } from 'preact/hooks'; import { useState } from 'preact/hooks';
import Spinner from '../Spinner';
export default function ForgotPasswordForm() { export default function ForgotPasswordForm() {
const [email, setEmail] = useState(''); const [email, setEmail] = useState('');
@ -105,29 +106,7 @@ export default function ForgotPasswordForm() {
disabled={isLoading} disabled={isLoading}
className="mt-2 inline-flex h-10 w-full items-center justify-center rounded-lg border border-slate-300 bg-black p-2 px-4 text-sm font-medium text-white outline-none transition duration-150 ease-in-out focus:ring-2 focus:ring-black focus:ring-offset-1 disabled:cursor-not-allowed disabled:opacity-60" className="mt-2 inline-flex h-10 w-full items-center justify-center rounded-lg border border-slate-300 bg-black p-2 px-4 text-sm font-medium text-white outline-none transition duration-150 ease-in-out focus:ring-2 focus:ring-black focus:ring-offset-1 disabled:cursor-not-allowed disabled:opacity-60"
> >
{isLoading ? ( {isLoading ? <Spinner className="text-white" /> : 'Continue'}
<svg
className={`h-5 w-5 animate-spin text-white`}
xmlns="http://www.w3.org/2000/svg"
fill="none"
viewBox="0 0 24 24"
>
<circle
className="stroke-[4px] opacity-25"
cx="12"
cy="12"
r="10"
stroke="currentColor"
></circle>
<path
className="opacity-75"
fill="currentColor"
d="M4 12a8 8 0 018-8V0C5.373 0 0 5.373 0 12h4zm2 5.291A7.962 7.962 0 014 12H0c0 3.042 1.135 5.824 3 7.938l3-2.647z"
></path>
</svg>
) : (
'Continue'
)}
</button> </button>
</form> </form>
); );

@ -1,4 +1,5 @@
import { useState } from 'preact/hooks'; import { useState } from 'preact/hooks';
import Spinner from '../Spinner';
export default function ResetPasswordForm() { export default function ResetPasswordForm() {
const [password, setPassword] = useState(''); const [password, setPassword] = useState('');
@ -127,29 +128,7 @@ export default function ResetPasswordForm() {
type="submit" type="submit"
className="mt-5 inline-flex h-10 w-full items-center justify-center rounded-lg border border-slate-300 bg-black p-2 px-4 text-sm font-medium text-white outline-none transition duration-150 ease-in-out focus:ring-2 focus:ring-black focus:ring-offset-1 disabled:cursor-not-allowed disabled:opacity-60" className="mt-5 inline-flex h-10 w-full items-center justify-center rounded-lg border border-slate-300 bg-black p-2 px-4 text-sm font-medium text-white outline-none transition duration-150 ease-in-out focus:ring-2 focus:ring-black focus:ring-offset-1 disabled:cursor-not-allowed disabled:opacity-60"
> >
{isLoading ? ( {isLoading ? <Spinner className="text-white" /> : 'Reset my password'}
<svg
className={`h-5 w-5 animate-spin text-white`}
xmlns="http://www.w3.org/2000/svg"
fill="none"
viewBox="0 0 24 24"
>
<circle
className="stroke-[4px] opacity-25"
cx="12"
cy="12"
r="10"
stroke="currentColor"
></circle>
<path
className="opacity-75"
fill="currentColor"
d="M4 12a8 8 0 018-8V0C5.373 0 0 5.373 0 12h4zm2 5.291A7.962 7.962 0 014 12H0c0 3.042 1.135 5.824 3 7.938l3-2.647z"
></path>
</svg>
) : (
'Reset my password'
)}
</button> </button>
</form> </form>
); );

@ -1,6 +1,7 @@
import { useCallback, useEffect, useState } from 'preact/hooks'; import { useCallback, useEffect, useState } from 'preact/hooks';
import Cookies from 'js-cookie'; import Cookies from 'js-cookie';
import { TOKEN_COOKIE_NAME } from '../../lib/constants'; import { TOKEN_COOKIE_NAME } from '../../lib/constants';
import Spinner from '../Spinner';
export default function ChangePasswordForm() { export default function ChangePasswordForm() {
const [authProvider, setAuthProvider] = useState< const [authProvider, setAuthProvider] = useState<
@ -210,29 +211,7 @@ export default function ChangePasswordForm() {
type="submit" type="submit"
disabled={isLoading} disabled={isLoading}
> >
{isLoading ? ( {isLoading ? <Spinner className="text-white" /> : 'Change'}
<svg
class={`h-5 w-5 animate-spin text-white`}
xmlns="http://www.w3.org/2000/svg"
fill="none"
viewBox="0 0 24 24"
>
<circle
class="stroke-[4px] opacity-25"
cx="12"
cy="12"
r="10"
stroke="currentColor"
></circle>
<path
class="opacity-75"
fill="currentColor"
d="M4 12a8 8 0 018-8V0C5.373 0 0 5.373 0 12h4zm2 5.291A7.962 7.962 0 014 12H0c0 3.042 1.135 5.824 3 7.938l3-2.647z"
></path>
</svg>
) : (
'Change'
)}
</button> </button>
</div> </div>
</form> </form>

@ -1,6 +1,7 @@
import { useCallback, useEffect, useState } from 'preact/hooks'; import { useCallback, useEffect, useState } from 'preact/hooks';
import { TOKEN_COOKIE_NAME } from '../../lib/constants'; import { TOKEN_COOKIE_NAME } from '../../lib/constants';
import Cookies from 'js-cookie'; import Cookies from 'js-cookie';
import Spinner from '../Spinner';
export default function UpdateProfileForm() { export default function UpdateProfileForm() {
const [name, setName] = useState(''); const [name, setName] = useState('');
@ -232,29 +233,7 @@ export default function UpdateProfileForm() {
type="submit" type="submit"
disabled={isLoading} disabled={isLoading}
> >
{isLoading ? ( {isLoading ? <Spinner className="text-white" /> : 'Update'}
<svg
class={`h-5 w-5 animate-spin text-white`}
xmlns="http://www.w3.org/2000/svg"
fill="none"
viewBox="0 0 24 24"
>
<circle
class="stroke-[4px] opacity-25"
cx="12"
cy="12"
r="10"
stroke="currentColor"
></circle>
<path
class="opacity-75"
fill="currentColor"
d="M4 12a8 8 0 018-8V0C5.373 0 0 5.373 0 12h4zm2 5.291A7.962 7.962 0 014 12H0c0 3.042 1.135 5.824 3 7.938l3-2.647z"
></path>
</svg>
) : (
'Update'
)}
</button> </button>
</div> </div>
</form> </form>

@ -4,22 +4,26 @@ const { ...props } = Astro.props;
export type Props = astroHTML.JSX.HTMLAttributes & {}; export type Props = astroHTML.JSX.HTMLAttributes & {};
--- ---
<svg <div role='status'>
xmlns='http://www.w3.org/2000/svg' <svg
fill='none' aria-hidden='true'
viewBox='0 0 24 24' xmlns='http://www.w3.org/2000/svg'
class:list={[`animate-spin h-5 w-5`, props.class]} fill='none'
{...props} viewBox='0 0 24 24'
> class:list={[`animate-spin h-5 w-5`, props.class]}
<circle {...props}
class='stroke-[4px] opacity-25' >
cx='12' <circle
cy='12' class='stroke-[4px] opacity-25'
r='10' cx='12'
stroke='currentColor'></circle> cy='12'
<path r='10'
class='opacity-75' stroke='currentColor'></circle>
fill='currentColor' <path
d='M4 12a8 8 0 018-8V0C5.373 0 0 5.373 0 12h4zm2 5.291A7.962 7.962 0 014 12H0c0 3.042 1.135 5.824 3 7.938l3-2.647z' class='opacity-75'
></path> fill='currentColor'
</svg> d='M4 12a8 8 0 018-8V0C5.373 0 0 5.373 0 12h4zm2 5.291A7.962 7.962 0 014 12H0c0 3.042 1.135 5.824 3 7.938l3-2.647z'
></path>
</svg>
<span class='sr-only'>Loading</span>
</div>

@ -0,0 +1,26 @@
export default function Spinner({ className }: { className?: string }) {
return (
<div role="status">
<svg
className={`h-5 w-5 animate-spin ${className}`}
xmlns="http://www.w3.org/2000/svg"
fill="none"
viewBox="0 0 24 24"
>
<circle
className="stroke-[4px] opacity-25"
cx="12"
cy="12"
r="10"
stroke="currentColor"
></circle>
<path
className="opacity-75"
fill="currentColor"
d="M4 12a8 8 0 018-8V0C5.373 0 0 5.373 0 12h4zm2 5.291A7.962 7.962 0 014 12H0c0 3.042 1.135 5.824 3 7.938l3-2.647z"
></path>
</svg>
<span class="sr-only">Loading</span>
</div>
);
}
Loading…
Cancel
Save