Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
20 changes: 15 additions & 5 deletions src/app/[locale]/admissions/_components/admissions-advisor.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,7 @@ export function AdmissionsAdvisor({ locale }: { locale: Locale }) {
)
const [editing, setEditing] = useState(true)
const [undoValues, setUndoValues] = useState<FormValues | null>(null)
const pendingFocus = useRef<string | null>(null)
const { saved, toggle, storageError } = useFavourites()
const [, setQueryState] = useQueryStates(resultParsers, resultQueryOptions)
const [{ answers }, setAnswerQuery] = useQueryStates(
Expand Down Expand Up @@ -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<HTMLElement>(`[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
Expand Down
20 changes: 12 additions & 8 deletions src/app/[locale]/admissions/_components/admissions-guide.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -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"
Expand All @@ -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"
>
<div className="page-content grid gap-10 lg:grid-cols-[0.7fr_1.3fr] lg:gap-16">
<div className="page-content grid grid-cols-1 gap-10 lg:grid-cols-[minmax(0,0.7fr)_minmax(0,1.3fr)] lg:gap-16">
<div>
<p className="flex items-center gap-2 font-medium text-primary text-sm">
<BookOpen aria-hidden="true" className="size-4" />
Expand Down Expand Up @@ -93,7 +94,7 @@ export async function AdmissionsGuide({
aria-labelledby="admissions-faq-title"
className="scroll-mt-6 border-t bg-background-light py-14 sm:py-20"
>
<div className="page-content grid items-start gap-10 lg:grid-cols-[0.7fr_1.3fr] lg:gap-16">
<div className="page-content grid grid-cols-1 items-start gap-10 lg:grid-cols-[minmax(0,0.7fr)_minmax(0,1.3fr)] lg:gap-16">
<div>
<p className="flex items-center gap-2 font-medium text-primary text-sm">
<HelpCircle aria-hidden="true" className="size-4" />
Expand Down Expand Up @@ -181,7 +182,7 @@ export async function AdmissionsGuide({
>
{t(`sourceGroups.${group.id}`)}
</h3>
<div className="grid gap-4 md:grid-cols-2 xl:grid-cols-4">
<div className="grid grid-cols-1 gap-4 md:grid-cols-2 xl:grid-cols-4">
{data.sources
.filter((source) =>
group.announcements.some(
Expand Down Expand Up @@ -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,
Expand Down Expand Up @@ -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")}
<ArrowUpRight
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,7 @@ export async function AdmissionsPage({
</SiteHeader>
<main
id="main-content"
className="min-h-svh bg-background-light text-foreground"
className="wrap-anywhere min-h-svh bg-background-light text-foreground"
>
<section
className="page-hero-section"
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -38,12 +38,12 @@ export function AdmissionsSelect<Value extends string>({
>
<SelectTrigger
disabled={disabled}
className="h-auto min-h-11 w-full min-w-0 whitespace-normal"
className="wrap-anywhere min-h-11 w-full min-w-0 whitespace-normal data-[size=default]:h-auto *:data-[slot=select-value]:line-clamp-none"
{...props}
>
<SelectValue className="min-w-0" />
</SelectTrigger>
<SelectContent alignItemWithTrigger={false}>
<SelectContent alignItemWithTrigger={false} className="wrap-anywhere">
<SelectGroup>
{items.map((item) => (
<SelectItem
Expand Down
17 changes: 10 additions & 7 deletions src/app/[locale]/admissions/_components/marks-form.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -198,7 +198,7 @@ export function MarksForm({
onSubmit(parsed.input)
}
return (
<div className="grid items-start gap-8 lg:grid-cols-[minmax(0,1.2fr)_minmax(0,0.8fr)] lg:gap-14">
<div className="grid grid-cols-1 items-start gap-8 lg:grid-cols-[minmax(0,1.2fr)_minmax(0,0.8fr)] lg:gap-14">
<form onSubmit={submit} noValidate autoComplete="off" aria-busy={loading}>
<Card>
<CardHeader>
Expand Down Expand Up @@ -509,7 +509,7 @@ export function MarksForm({
</Alert>
) : null}
{maximum ? (
<FieldSet>
<FieldSet className="min-w-0">
<FieldLegend id="score-mode-label" variant="label">
{t("form.inputMode")}
</FieldLegend>
Expand All @@ -524,16 +524,19 @@ export function MarksForm({
}
}}
variant="outline"
spacing={0}
className="w-full"
spacing={1}
className="w-full flex-wrap items-stretch"
>
<ToggleGroupItem
value="percentage"
className="min-h-11 flex-1"
className="wrap-anywhere h-auto min-h-11 min-w-0 flex-1 basis-24 whitespace-normal py-2"
>
{t("form.percentage")}
</ToggleGroupItem>
<ToggleGroupItem value="total" className="min-h-11 flex-1">
<ToggleGroupItem
value="total"
className="wrap-anywhere h-auto min-h-11 min-w-0 flex-1 basis-24 whitespace-normal py-2"
>
{t("form.total", { maximum })}
</ToggleGroupItem>
</ToggleGroup>
Expand Down Expand Up @@ -820,7 +823,7 @@ export function MarksForm({
<Button
type="submit"
size="lg"
className="min-h-12"
className="h-auto min-h-12 whitespace-normal py-3"
disabled={
loading ||
unsupportedSharia ||
Expand Down
7 changes: 5 additions & 2 deletions src/app/[locale]/admissions/_components/results-lookup.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -196,7 +196,10 @@ export function ResultsLookup({
size,
appearance: "interaction-only",
language: locale,
callback: setToken,
callback: (nextToken) => {
setToken(nextToken)
setError((current) => (current === "challenge" ? "" : current))
},
"expired-callback": () => setToken(""),
"error-callback": () => {
setToken("")
Expand Down Expand Up @@ -403,7 +406,7 @@ export function ResultsLookup({
) : null}
{error ? (
<Alert variant="destructive">
<AlertDescription role="alert">
<AlertDescription>
{t(`errors.${error as "unavailable"}`)}
</AlertDescription>
</Alert>
Expand Down
4 changes: 2 additions & 2 deletions src/components/faq-accordion.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -23,11 +23,11 @@ export function FaqAccordion({ items }: FaqAccordionProps) {
multiple
defaultValue={items.slice(0, 1).map((item) => item.id)}
hiddenUntilFound
className="rounded-xl border bg-card px-5 sm:px-6"
className="wrap-anywhere rounded-xl border bg-card px-5 sm:px-6"
>
{items.map((item) => (
<AccordionItem value={item.id} key={item.id}>
<AccordionTrigger className="py-5 text-base leading-7">
<AccordionTrigger className="min-w-0 py-5 text-base leading-7">
{item.question}
</AccordionTrigger>
<AccordionContent>
Expand Down
12 changes: 6 additions & 6 deletions src/components/site-footer.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -24,8 +24,8 @@ export async function SiteFooter({ locale }: SiteFooterProps) {

return (
<footer className="border-t bg-background py-10 text-foreground sm:py-12">
<div className={cn("page-content", "grid gap-9")}>
<div className="grid gap-8 lg:grid-cols-[minmax(0,1fr)_minmax(36rem,1.5fr)]">
<div className={cn("page-content", "grid grid-cols-1 gap-9")}>
<div className="grid grid-cols-1 gap-8 lg:grid-cols-[minmax(0,1fr)_minmax(0,1.5fr)]">
<div>
<Link
aria-label="OpenSyria"
Expand All @@ -43,7 +43,7 @@ export async function SiteFooter({ locale }: SiteFooterProps) {
</div>

<nav aria-label={t("navigationLabel")}>
<div className="grid gap-7 sm:grid-cols-3">
<div className="grid grid-cols-1 gap-7 sm:grid-cols-3">
<FooterLinkGroup title={t("platformTitle")}>
<li>
<Link className={footerLinkClassName} href="/">
Expand Down Expand Up @@ -149,7 +149,7 @@ export async function SiteFooter({ locale }: SiteFooterProps) {
<h2 className="font-heading font-semibold text-sm">
{t("repositoriesTitle")}
</h2>
<ul className="mt-4 grid list-none gap-x-9 gap-y-5 sm:grid-cols-2 lg:grid-cols-3 xl:grid-cols-4">
<ul className="mt-4 grid list-none grid-cols-1 gap-x-9 gap-y-5 sm:grid-cols-2 lg:grid-cols-3 xl:grid-cols-4">
{github.repositories.map((repository) => (
<li key={repository.name} className="min-w-0">
<a
Expand Down Expand Up @@ -196,10 +196,10 @@ function FooterLinkGroup({
return (
<section aria-label={title}>
<h2 className="font-heading font-semibold text-sm">{title}</h2>
<ul className="mt-4 grid list-none gap-3">{children}</ul>
<ul className="mt-4 grid list-none grid-cols-1 gap-3">{children}</ul>
</section>
)
}

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"
2 changes: 1 addition & 1 deletion src/components/site-header.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ export function SiteHeader({ children, className }: SiteHeaderProps) {
<div
className={cn(
"page-content",
"flex items-center justify-between gap-4"
"flex flex-wrap items-center justify-between gap-4"
)}
>
<Link
Expand Down