Symmetri i huvudet och i knapparna
Navigationen trycktes ihop mot högerkanten med ett tomrum efter ordmärket. På smal skärm ligger den nu på egen rad och fördelas över hela måttet — samma fördelning som sidfoten redan använder. Raden får sin balans av marginalerna i stället för av att posterna klumpas ihop. Mätt: noll pixlar kvar på bägge sidor. Portalens sex länkar blir på 360 px en tvåkolumnsindex, vilket läser sig som avsikt och inte som spill. Knapparna var innehållsbreda, så REQUEST ACCOUNT blev dubbelt så bred som LOGIN. Två knappar bredvid varandra där den ena är dubbelt så bred läser sig som en huvudåtgärd och en eftertanke, oavsett vad de heter — och det är inte förhållandet mellan dem. Rutnätet ger dem samma bredd; vikten skiljs av fyllning mot kontur, som resten av systemet gör. Lika bredd räckte inte: REQUEST ACCOUNT bryts till två rader och knapparna blev då olika HÖGA, vilket är samma obalans en rad ned. Bägge fyller nu sin cell. Mätt: 163x57 mot 163x57. ---- Och ett test som slutade mäta ------------------------------------- Namntestet från förra ändringen matchade markup-formen, inte invarianten. När <Link> fick en className hittade mönstret noll knappar — testet slutade mäta i stället för att falla. Det enda som avslöjade det var kravet att det ska hitta NÅGOT, och det är därför kravet står där i stället för att tas för givet. Mutationstestat igen efter rättelsen: bägge testen faller när "Customer login" läggs tillbaka. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_012EQg3rJsrQ1ZNTvkzmQAtt
This commit is contained in:
@@ -303,12 +303,21 @@ export function Knapp({
|
|||||||
onClick,
|
onClick,
|
||||||
variant = "primar",
|
variant = "primar",
|
||||||
disabled,
|
disabled,
|
||||||
|
bred = false,
|
||||||
type = "button",
|
type = "button",
|
||||||
}: {
|
}: {
|
||||||
children: ReactNode;
|
children: ReactNode;
|
||||||
onClick?: () => void;
|
onClick?: () => void;
|
||||||
variant?: "primar" | "sekundar";
|
variant?: "primar" | "sekundar";
|
||||||
disabled?: boolean;
|
disabled?: boolean;
|
||||||
|
/**
|
||||||
|
* Fyller sin behållare i stället för att vara innehållsbred.
|
||||||
|
*
|
||||||
|
* För knappar som står bredvid varandra: två olika breda knappar läser
|
||||||
|
* sig som en huvudåtgärd och en eftertanke, oavsett vad de heter. Med
|
||||||
|
* lika bredd skiljs vikten av fyllning mot kontur i stället.
|
||||||
|
*/
|
||||||
|
bred?: boolean;
|
||||||
type?: "button" | "submit";
|
type?: "button" | "submit";
|
||||||
}) {
|
}) {
|
||||||
const primär = variant === "primar";
|
const primär = variant === "primar";
|
||||||
@@ -317,7 +326,12 @@ export function Knapp({
|
|||||||
type={type}
|
type={type}
|
||||||
onClick={onClick}
|
onClick={onClick}
|
||||||
disabled={disabled}
|
disabled={disabled}
|
||||||
className="border px-4 py-2 text-[13px] font-semibold uppercase tracking-[0.08em] disabled:opacity-40"
|
// `h-full` och inte bara `w-full`: lika breda knappar där den ena
|
||||||
|
// texten bryts till två rader blir olika HÖGA, vilket är samma
|
||||||
|
// obalans en rad ned. Bägge fyller sin cell.
|
||||||
|
className={`border px-4 py-2 text-[13px] font-semibold uppercase tracking-[0.08em] disabled:opacity-40${
|
||||||
|
bred ? " h-full w-full" : ""
|
||||||
|
}`}
|
||||||
style={{
|
style={{
|
||||||
background: primär ? FARG.graphite : FARG.white,
|
background: primär ? FARG.graphite : FARG.white,
|
||||||
color: primär ? FARG.white : FARG.graphite,
|
color: primär ? FARG.white : FARG.graphite,
|
||||||
|
|||||||
@@ -416,7 +416,13 @@ describe("inloggningen heter samma sak överallt", () => {
|
|||||||
const namn = ram.match(/\{ till: "\/alva\/logga-in", text: "([^"]+)" \}/)?.[1];
|
const namn = ram.match(/\{ till: "\/alva\/logga-in", text: "([^"]+)" \}/)?.[1];
|
||||||
expect(namn).toBeTruthy();
|
expect(namn).toBeTruthy();
|
||||||
// Varje länk till inloggningen på startsidan bär samma text.
|
// Varje länk till inloggningen på startsidan bär samma text.
|
||||||
const knappar = [...start.matchAll(/to="\/alva\/logga-in">\s*<Knapp[^>]*>([^<]+)<\/Knapp>/g)];
|
//
|
||||||
|
// Mönstret tål attribut på länken. Första versionen gjorde inte det,
|
||||||
|
// och när <Link> fick en className matchade den noll knappar — testet
|
||||||
|
// slutade mäta i stället för att falla. Det enda som avslöjade det var
|
||||||
|
// kravet nedan på att den ska hitta NÅGOT, vilket är därför det står
|
||||||
|
// där och inte som en självklarhet.
|
||||||
|
const knappar = [...start.matchAll(/to="\/alva\/logga-in"[^>]*>\s*<Knapp[^>]*>([^<]+)<\/Knapp>/g)];
|
||||||
expect(knappar.length).toBeGreaterThan(0);
|
expect(knappar.length).toBeGreaterThan(0);
|
||||||
for (const [, text] of knappar) expect(text.trim()).toBe(namn);
|
for (const [, text] of knappar) expect(text.trim()).toBe(namn);
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -49,11 +49,16 @@ export function Ram({ children, portal = false }: { children: ReactNode; portal?
|
|||||||
</span>
|
</span>
|
||||||
</Link>
|
</Link>
|
||||||
|
|
||||||
{/* Portalens fem länkar fick inte plats på en telefon och sköt
|
{/* Portalens länkar fick inte plats på en telefon och sköt ut
|
||||||
ut dokumentet i sidled i stället för att brytas. Raden bryts
|
dokumentet i sidled i stället för att brytas. Raden bryts nu.
|
||||||
nu, med tätare mellanrum på smal skärm. */}
|
|
||||||
<nav aria-label={portal ? "Portal" : "Site"}>
|
På smal skärm ligger navigationen dessutom på EGEN rad och
|
||||||
<ul className="flex flex-wrap gap-2 sm:gap-6">
|
fördelas över hela måttet, i stället för att tryckas ihop mot
|
||||||
|
höger kant med ett tomrum efter ordmärket. Det är samma
|
||||||
|
fördelning som sidfoten redan använder — raden får sin balans
|
||||||
|
av marginalerna, inte av att posterna klumpas ihop. */}
|
||||||
|
<nav aria-label={portal ? "Portal" : "Site"} className="w-full sm:w-auto">
|
||||||
|
<ul className="flex flex-wrap justify-between gap-x-4 gap-y-2 sm:justify-end sm:gap-6">
|
||||||
{lankar.map((l) => {
|
{lankar.map((l) => {
|
||||||
const aktiv = plats.pathname === l.till;
|
const aktiv = plats.pathname === l.till;
|
||||||
return (
|
return (
|
||||||
|
|||||||
@@ -51,12 +51,17 @@ export default function Start() {
|
|||||||
{ALVA.definition}
|
{ALVA.definition}
|
||||||
</p>
|
</p>
|
||||||
|
|
||||||
<div className="mt-10 flex gap-4">
|
{/* Lika breda, inte innehållsbreda. Två knappar bredvid varandra
|
||||||
<Link to="/alva/ansokan">
|
där den ena är dubbelt så bred som den andra läser sig som en
|
||||||
<Knapp>Request account</Knapp>
|
huvudåtgärd och en eftertanke — och det är inte förhållandet
|
||||||
|
mellan dem. Rutnätet ger dem samma bredd; vikten skiljs av
|
||||||
|
fyllning mot kontur, som resten av systemet gör. */}
|
||||||
|
<div className="mt-10 grid max-w-[420px] grid-cols-2 gap-4">
|
||||||
|
<Link to="/alva/ansokan" className="block h-full">
|
||||||
|
<Knapp bred>Request account</Knapp>
|
||||||
</Link>
|
</Link>
|
||||||
<Link to="/alva/logga-in">
|
<Link to="/alva/logga-in" className="block h-full">
|
||||||
<Knapp variant="sekundar">Login</Knapp>
|
<Knapp bred variant="sekundar">Login</Knapp>
|
||||||
</Link>
|
</Link>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@@ -278,12 +283,12 @@ export default function Start() {
|
|||||||
<div className="font-mono text-[11px]" style={{ color: FARG.steel }}>
|
<div className="font-mono text-[11px]" style={{ color: FARG.steel }}>
|
||||||
{PLATTFORMSVERSION}
|
{PLATTFORMSVERSION}
|
||||||
</div>
|
</div>
|
||||||
<div className="flex gap-4">
|
<div className="grid max-w-[420px] grid-cols-2 gap-4">
|
||||||
<Link to="/alva/ansokan">
|
<Link to="/alva/ansokan" className="block h-full">
|
||||||
<Knapp>Request account</Knapp>
|
<Knapp bred>Request account</Knapp>
|
||||||
</Link>
|
</Link>
|
||||||
<Link to="/alva/logga-in">
|
<Link to="/alva/logga-in" className="block h-full">
|
||||||
<Knapp variant="sekundar">Login</Knapp>
|
<Knapp bred variant="sekundar">Login</Knapp>
|
||||||
</Link>
|
</Link>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
Reference in New Issue
Block a user