diff --git a/CHANGELOG.md b/CHANGELOG.md index 34d9e75..f99bbc6 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -37,6 +37,9 @@ ### Bug Fixes +* keep admissions controls and the header usable with larger text, and clear recovered verification errors without hiding lookup failures +* focus the results or marks field after the new view renders, including when a previous language page is cached + * clarify pending eligibility and shared answers, align Arabic/English admission guidance, put common FAQ questions first, and correct source links and release-history placement * consolidate repeated eligibility inputs into one compact shared dialog opened from the applicable admission-track container, save answers globally through the URL, and restore reading position and focus after results regroup, including pagination and filtered-out choices diff --git a/src/app/[locale]/admissions/_components/admissions-advisor.tsx b/src/app/[locale]/admissions/_components/admissions-advisor.tsx index 1cbf101..1039f65 100644 --- a/src/app/[locale]/admissions/_components/admissions-advisor.tsx +++ b/src/app/[locale]/admissions/_components/admissions-advisor.tsx @@ -42,6 +42,7 @@ export function AdmissionsAdvisor({ locale }: { locale: Locale }) { ) const [editing, setEditing] = useState(true) const [undoValues, setUndoValues] = useState(null) + const pendingFocus = useRef(null) const { saved, toggle, storageError } = useFavourites() const [, setQueryState] = useQueryStates(resultParsers, resultQueryOptions) const [{ answers }, setAnswerQuery] = useQueryStates( @@ -127,12 +128,21 @@ export function AdmissionsAdvisor({ locale }: { locale: Locale }) { /* Answers remain usable in memory when storage is unavailable. */ } }, [currentValues]) + // Wait for the requested form/results view to commit before finding its target. + // A cached, hidden locale can contain the same IDs as the active page. + useLayoutEffect(() => { + const id = pendingFocus.current + if (!id) return + const element = Array.from( + document.querySelectorAll(`[id="${id}"]`) + ).find((candidate) => candidate.getClientRects().length > 0) + if (!element) return + pendingFocus.current = null + element.focus({ preventScroll: true }) + element.scrollIntoView({ block: "start" }) + }) function focus(id: string) { - requestAnimationFrame(() => { - const element = document.getElementById(id) - element?.focus({ preventScroll: true }) - element?.scrollIntoView({ block: "start" }) - }) + pendingFocus.current = id } function answerCondition(answer: ConfirmationAnswer) { const previous = answerValues.current diff --git a/src/app/[locale]/admissions/_components/admissions-guide.tsx b/src/app/[locale]/admissions/_components/admissions-guide.tsx index 2bc7982..aecd01c 100644 --- a/src/app/[locale]/admissions/_components/admissions-guide.tsx +++ b/src/app/[locale]/admissions/_components/admissions-guide.tsx @@ -13,6 +13,7 @@ import { } from "@/components/ui/card" import type { Locale } from "@/i18n/routing" import { trustedExternalLinkRel } from "@/lib/links" +import { cn } from "@/lib/utils" import { faqItems, guideSections, sourceGroups } from "../_utils/content" import type { AdmissionsData } from "../_utils/types" import { SourceLinks } from "./source-links" @@ -32,7 +33,7 @@ export async function AdmissionsGuide({ aria-labelledby="admissions-guide-title" className="scroll-mt-6 border-t bg-background py-14 sm:py-20" > -
+

+

+
{data.sources .filter((source) => group.announcements.some( @@ -214,10 +215,10 @@ export async function AdmissionsGuide({ href={source.url} target="_blank" rel={trustedExternalLinkRel} - className={buttonVariants({ - variant: "outline", - size: "sm", - })} + className={cn( + buttonVariants({ variant: "outline", size: "sm" }), + "wrap-anywhere h-auto min-h-8 max-w-full whitespace-normal py-1.5" + )} > {t("readAnnouncement", { number: source.announcement, @@ -247,7 +248,10 @@ export async function AdmissionsGuide({ href="https://mofa.education-syria.com/signup" target="_blank" rel={trustedExternalLinkRel} - className={buttonVariants({ variant: "outline", size: "lg" })} + className={cn( + buttonVariants({ variant: "outline", size: "lg" }), + "wrap-anywhere h-auto min-h-10 max-w-full whitespace-normal py-2" + )} > {t("applicationLink")}
({ > - + {items.map((item) => ( +
@@ -509,7 +509,7 @@ export function MarksForm({ ) : null} {maximum ? ( -
+
{t("form.inputMode")} @@ -524,16 +524,19 @@ export function MarksForm({ } }} variant="outline" - spacing={0} - className="w-full" + spacing={1} + className="w-full flex-wrap items-stretch" > {t("form.percentage")} - + {t("form.total", { maximum })} @@ -820,7 +823,7 @@ export function MarksForm({
) } const footerLinkClassName = - "inline-flex items-center gap-1.5 rounded-md text-muted-foreground text-sm transition hover:text-primary focus-visible:outline-none focus-visible:ring-3 focus-visible:ring-ring/50" + "inline-flex max-w-full items-center gap-1.5 rounded-md text-muted-foreground text-sm wrap-anywhere transition hover:text-primary focus-visible:outline-none focus-visible:ring-3 focus-visible:ring-ring/50" diff --git a/src/components/site-header.tsx b/src/components/site-header.tsx index cfab6ff..a5938e7 100644 --- a/src/components/site-header.tsx +++ b/src/components/site-header.tsx @@ -19,7 +19,7 @@ export function SiteHeader({ children, className }: SiteHeaderProps) {