diff --git a/apps/frontend/package.json b/apps/frontend/package.json index 0a1590bfbb909..89e43f0c651e9 100644 --- a/apps/frontend/package.json +++ b/apps/frontend/package.json @@ -25,7 +25,6 @@ "react": "^19.2.8", "react-dom": "^19.2.8", "react-icons": "^5.7.0", - "react-loading-skeleton": "^3.5.0", "react-redux": "^9.3.0", "react-spinners": "^0.17.0", "react-toastify": "^11.1.0", diff --git a/apps/frontend/src/index.css b/apps/frontend/src/index.css index 14ae121a249c8..bb35398d922a9 100644 --- a/apps/frontend/src/index.css +++ b/apps/frontend/src/index.css @@ -29,6 +29,7 @@ Override background color in dark mode with GitHub's dark mode background color. --transition-fast: 100ms; /* Slower, deliberate fade for large surfaces during a theme switch. */ --transition-surface: 300ms; + --font-size: 16px; } /* @@ -110,6 +111,28 @@ Override background color in dark mode with GitHub's dark mode background color. outline: 0; border: var(--color-primary) solid 1px; } + + /* daisyUI's disabled border matches its own background and its text sits at 2.5:1. */ + .input:is(:disabled, [disabled]) { + border-color: color-mix( + in oklab, + var(--color-base-content) 20%, + transparent + ); + + &:is(input), + & :is(input) { + color: color-mix(in oklab, var(--color-base-content) 65%, transparent); + } + } + + /* + * `.validator` makes `:user-valid` fields green. We only want to color the error state, + * so restore `--input-color` to the value `.input` uses by default. + */ + .validator:user-valid { + --input-color: color-mix(in oklab, var(--color-base-content) 20%, #0000); + } } /* Respect users who prefer reduced motion. */ diff --git a/apps/frontend/src/wizard/Home/stages/Customize.tsx b/apps/frontend/src/wizard/Home/stages/Customize.tsx index e43a2bdeeb800..21a9ef97d99a9 100644 --- a/apps/frontend/src/wizard/Home/stages/Customize.tsx +++ b/apps/frontend/src/wizard/Home/stages/Customize.tsx @@ -414,7 +414,7 @@ export function CustomizeStage({
-
+
diff --git a/apps/frontend/src/wizard/Home/stages/Display.tsx b/apps/frontend/src/wizard/Home/stages/Display.tsx index e3bb981831679..1f87526791200 100644 --- a/apps/frontend/src/wizard/Home/stages/Display.tsx +++ b/apps/frontend/src/wizard/Home/stages/Display.tsx @@ -101,7 +101,7 @@ export function DisplayStage({
, - action: () => void, -) { - useEffect(() => { - /** - * Alert if clicked on outside of element - */ - function handleClickOutside(event: MouseEvent) { - if (ref.current && !ref.current.contains(event.target as Node)) { - action(); - } - } - - // Bind the event listener - document.addEventListener("mousedown", handleClickOutside); - - return () => { - // Unbind the event listener on clean up - document.removeEventListener("mousedown", handleClickOutside); - }; - }, [action, ref]); -} - interface LoginAccountDeleteModalProps { onClose: () => void; onConfirm: () => void; @@ -38,36 +13,44 @@ export function LoginAccountDeleteModal( ): JSX.Element { const { onConfirm, onClose } = props; - const wrapperRef = useRef(null); - useOutsideAlerter(wrapperRef, onClose); - - return createPortal( - // `wizard` because this mounts on `body`, outside the element the app's styles are scoped to. -
-
-
-

Delete Account

-
-
-

- Are you sure you want to delete your account from GitHub Stats - Extended? -

-
-
- - -
+ const titleId = useId(); + + return ( + { + if (node !== null && !node.open) { + node.showModal(); + } + }} + className="modal" + aria-labelledby={titleId} + onClose={onClose} + > +
+

+ Delete Account +

+
+
+

+ Are you sure you want to delete your account from GitHub Stats + Extended? +

+
+
+ +
-
, - document.body, + {/* daisyUI's backdrop: submitting it closes the dialog, so a click outside dismisses. */} +
+ +
+ ); } diff --git a/apps/frontend/src/wizard/Home/stages/Login/LoginAccountManagement.tsx b/apps/frontend/src/wizard/Home/stages/Login/LoginAccountManagement.tsx index d5792a6b578e8..4120c24e9a98e 100644 --- a/apps/frontend/src/wizard/Home/stages/Login/LoginAccountManagement.tsx +++ b/apps/frontend/src/wizard/Home/stages/Login/LoginAccountManagement.tsx @@ -49,7 +49,7 @@ export function LoginAccountManagement(): JSX.Element { }; return ( - +
{privateAccess ? (
diff --git a/apps/frontend/src/wizard/Home/stages/Login/LoginBox.tsx b/apps/frontend/src/wizard/Home/stages/Login/LoginBox.tsx index c69bfb82a6c5b..b853eb9de97ab 100644 --- a/apps/frontend/src/wizard/Home/stages/Login/LoginBox.tsx +++ b/apps/frontend/src/wizard/Home/stages/Login/LoginBox.tsx @@ -1,20 +1,17 @@ -import { clsx } from "clsx"; import type { JSX, ReactNode } from "react"; import { LoginBoxDemoCards } from "./LoginBoxDemoCards"; interface LoginBoxProps { children: ReactNode; - - isOpaque?: boolean; } export function LoginBox(props: LoginBoxProps): JSX.Element { - const { children, isOpaque = false } = props; + const { children } = props; return (
-
+
{children} diff --git a/apps/frontend/src/wizard/components/Card/SvgInline.tsx b/apps/frontend/src/wizard/components/Card/SvgInline.tsx index a42692132773c..2378f561e3135 100644 --- a/apps/frontend/src/wizard/components/Card/SvgInline.tsx +++ b/apps/frontend/src/wizard/components/Card/SvgInline.tsx @@ -2,8 +2,6 @@ import { loadConfigFromEnv } from "@stats-organization/github-readme-stats-core" import axios from "axios"; import { useEffect, useRef, useState } from "react"; import type { JSX } from "react"; -import Skeleton from "react-loading-skeleton"; -import "react-loading-skeleton/dist/skeleton.css"; import { setShouldMock } from "../../../axios-override.js"; import { @@ -103,13 +101,17 @@ export function SvgInline(props: SvgInlineProps): JSX.Element { if (forceLoading || !loaded) { if (compact) { return ( - +
); } // maximum dimensions of cards in SelectCard stage return ( -
- +
+
); } diff --git a/apps/frontend/src/wizard/components/Generic/Select.tsx b/apps/frontend/src/wizard/components/Generic/Select.tsx index c7a17bc2cb5bf..8acb92bfaaf8f 100644 --- a/apps/frontend/src/wizard/components/Generic/Select.tsx +++ b/apps/frontend/src/wizard/components/Generic/Select.tsx @@ -12,6 +12,8 @@ interface SelectProps { options: Array; selectedOption: SelectOption; + "aria-labelledby"?: string; + className?: string; disabled?: boolean; @@ -24,9 +26,11 @@ export function Select({ onOptionChange, disabled, className, + "aria-labelledby": ariaLabelledBy, }: SelectProps): JSX.Element { return ( +

{description}

{ setInputValue(e.target.value); @@ -49,6 +52,14 @@ export function NumericSection({ disabled={disabled} placeholder={placeholder} /> + {/* + * Hidden until the field is `:user-invalid`, then shown in the error color. + * The hint reserves its box either way and adds a gap no other `Section` has. + * Take that back out of `Section`'s `pb-12` with `h-0`. + */} +

+ Enter a number between {min} and {max}. +

); } diff --git a/apps/frontend/src/wizard/components/Home/Progress.tsx b/apps/frontend/src/wizard/components/Home/Progress.tsx index 6e9b9def16cbe..55a07332bf2f6 100644 --- a/apps/frontend/src/wizard/components/Home/Progress.tsx +++ b/apps/frontend/src/wizard/components/Home/Progress.tsx @@ -1,4 +1,5 @@ import { clsx } from "clsx"; +import { useEffect, useRef } from "react"; import type { JSX, MouseEventHandler } from "react"; import { FaArrowLeft as LeftArrowIcon, @@ -60,9 +61,38 @@ export function ProgressBar({ const leftDisabled = currItemIndex === 0; const rightDisabled = currItemIndex === items.length - 1; + const barRef = useRef(null); + + /* + * The bar resizes because the step labels wrap, so a panel stacking under it cannot use a fixed offset. + * Publish the measured height instead; `Customize` and `Display` pin their card against it. + */ + useEffect(() => { + const bar = barRef.current; + if (bar === null) { + return undefined; + } + + const observer = new ResizeObserver(() => { + document.documentElement.style.setProperty( + "--wizard-progress-height", + `${bar.getBoundingClientRect().height}px`, + ); + }); + observer.observe(bar); + + return () => { + observer.disconnect(); + document.documentElement.style.removeProperty("--wizard-progress-height"); + }; + }, []); + return ( // The site header is fixed, so the bar parks directly under it rather than at the viewport top. -
+