Ge ALVA-ytan sin egen typografi enligt ALVA-SPEC-001
ALVA satte inget eget snitt och ärvde därför värdapplikationens `Crimson Text` — en antikva. Specens paragraf 6 föreskriver DIN 2014, med FF DIN och IBM Plex Sans som tillåtna alternativ. Skillnaden är inte kosmetisk. Bokstavsformen är det första som säger vilken tradition ett verktyg tillhör, och dokumentet beskrev ett tyskt industrisystem medan skärmen visade en bokstavsform ur en helt annan. På en telefon, där ingenting annat konkurrerar om intrycket, var det i praktiken allt man såg. Fallkedjan är därför inte godtycklig: en organisation som licensierat DIN får DIN, övriga faller ned genom grotesker som delar dess karaktär, och aldrig till en antikva. Beteckningar och mätvärden sätts med fast teckenbredd och tabellsiffror — en beteckning jämförs oftare än den läses. Reglerna gäller bara ALVA-ytan; butiken lämnas som den är. Fyra tester låser snittet, kaskaden och siffrorna, inklusive att fallkedjan aldrig slutar i en antikva. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_012EQg3rJsrQ1ZNTvkzmQAtt
This commit is contained in:
@@ -168,3 +168,24 @@ export const PLATTFORMSVERSION = "ALVA 1.0";
|
|||||||
|
|
||||||
export const RUTNÄT = 8;
|
export const RUTNÄT = 8;
|
||||||
export const steg = (antal: number) => `${antal * RUTNÄT}px`;
|
export const steg = (antal: number) => `${antal * RUTNÄT}px`;
|
||||||
|
|
||||||
|
// ---- Typografi (ALVA-SPEC-001 · paragraf 6) ---------------------------
|
||||||
|
//
|
||||||
|
// En familj genomgående, åtskild med vikt, storlek, spärrning och
|
||||||
|
// versalisering. Produktionssnittet är DIN 2014; tillåtna alternativ är
|
||||||
|
// FF DIN och IBM Plex Sans. Ordningen nedan är därför inte godtycklig:
|
||||||
|
// en organisation som licensierat DIN får DIN, övriga faller ned genom
|
||||||
|
// grotesker som delar dess karaktär — aldrig till en antikva.
|
||||||
|
//
|
||||||
|
// Detta var länge ett avsteg i praktiken. ALVA-ytan satte inget eget
|
||||||
|
// snitt och ärvde därför värdapplikationens `Crimson Text` — en antikva.
|
||||||
|
// Specen beskrev ett tyskt industrisystem medan skärmen visade en
|
||||||
|
// bokstavsform från en helt annan tradition, och det syntes direkt på en
|
||||||
|
// telefon där ingenting annat konkurrerade om intrycket.
|
||||||
|
export const TYPSNITT =
|
||||||
|
'"DIN 2014", "FF DIN", "IBM Plex Sans", "Inter", "Helvetica Neue", Helvetica, Arial, system-ui, sans-serif';
|
||||||
|
|
||||||
|
// Identifierare och mätvärden sätts med fast teckenbredd så att siffror
|
||||||
|
// står i kolumn — beteckningar jämförs oftare än de läses.
|
||||||
|
export const TYPSNITT_MONO =
|
||||||
|
'ui-monospace, "IBM Plex Mono", "SF Mono", "Cascadia Mono", Menlo, Consolas, "Liberation Mono", monospace';
|
||||||
|
|||||||
@@ -156,3 +156,41 @@ describe("ALVA-ytan håller sig inom skärmbredden", () => {
|
|||||||
expect(komponenter).toContain("min-w-0 flex-1");
|
expect(komponenter).toContain("min-w-0 flex-1");
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
// ---- Typografin är specens, inte värdapplikationens --------------------
|
||||||
|
//
|
||||||
|
// ALVA-ytan satte länge inget eget snitt och ärvde därför butikens
|
||||||
|
// `Crimson Text` — en antikva. Specen (ALVA-SPEC-001, paragraf 6)
|
||||||
|
// föreskriver DIN 2014 med FF DIN och IBM Plex Sans som tillåtna
|
||||||
|
// alternativ. Skillnaden är inte kosmetisk: bokstavsformen är det första
|
||||||
|
// som säger vilken tradition ett verktyg tillhör, och på en telefon där
|
||||||
|
// ingenting annat konkurrerar om intrycket var det allt man såg.
|
||||||
|
describe("ALVA-ytan bär sin egen typografi", () => {
|
||||||
|
const css = readFileSync("src/index.css", "utf8");
|
||||||
|
const ram = filer.find(([n]) => n.endsWith("pages/alva/Ram.tsx"))![1];
|
||||||
|
const system = filer.find(([n]) => n.endsWith("alva/system.ts"))![1];
|
||||||
|
|
||||||
|
it("ramen märker ytan så att kaskaden når den", () => {
|
||||||
|
expect(ram).toContain("alva-yta");
|
||||||
|
});
|
||||||
|
|
||||||
|
it("snittet är deklarerat i systemfilen med specens ordning", () => {
|
||||||
|
const stack = system.match(/export const TYPSNITT =[\s\S]*?;/)?.[0] ?? "";
|
||||||
|
expect(stack).toContain("DIN 2014");
|
||||||
|
expect(stack).toContain("FF DIN");
|
||||||
|
expect(stack).toContain("IBM Plex Sans");
|
||||||
|
// Fallkedjan får aldrig sluta i en antikva. `sans-serif` är den
|
||||||
|
// generiska groteskfamiljen och alltså inte det som avses.
|
||||||
|
expect(stack).not.toMatch(/(?<!sans-)\bserif\b/);
|
||||||
|
});
|
||||||
|
|
||||||
|
it("regeln gäller ytan och når även rubriker", () => {
|
||||||
|
const regel = css.match(/\.alva-yta[\s\S]*?\{[\s\S]*?\}/)?.[0] ?? "";
|
||||||
|
expect(regel).toContain("DIN 2014");
|
||||||
|
expect(css).toContain(".alva-yta h1");
|
||||||
|
});
|
||||||
|
|
||||||
|
it("siffror sätts med fast bredd så beteckningar går att jämföra", () => {
|
||||||
|
expect(css).toContain("tabular-nums");
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|||||||
@@ -156,6 +156,57 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* ---- ALVA-ytan (ALVA-SPEC-001 · paragraf 6) --------------------------
|
||||||
|
*
|
||||||
|
* Värdapplikationen sätter en antikva på body. ALVA ärvde den, vilket är
|
||||||
|
* fel tradition för ett system som beskriver sig som ett tyskt
|
||||||
|
* industriverktyg. Reglerna nedan gäller bara ALVA-ytan; butiken lämnas
|
||||||
|
* som den är.
|
||||||
|
*
|
||||||
|
* Snittet deklareras i src/alva/system.ts och speglas här därför att
|
||||||
|
* kaskaden måste nå även de element komponenterna inte själva sätter
|
||||||
|
* stil på — rubriker fångas annars av värdapplikationens h1–h6-regel.
|
||||||
|
*/
|
||||||
|
.alva-yta,
|
||||||
|
.alva-yta h1,
|
||||||
|
.alva-yta h2,
|
||||||
|
.alva-yta h3,
|
||||||
|
.alva-yta h4,
|
||||||
|
.alva-yta h5,
|
||||||
|
.alva-yta h6,
|
||||||
|
.alva-yta button,
|
||||||
|
.alva-yta input,
|
||||||
|
.alva-yta select,
|
||||||
|
.alva-yta textarea {
|
||||||
|
font-family:
|
||||||
|
"DIN 2014",
|
||||||
|
"FF DIN",
|
||||||
|
"IBM Plex Sans",
|
||||||
|
"Inter",
|
||||||
|
"Helvetica Neue",
|
||||||
|
Helvetica,
|
||||||
|
Arial,
|
||||||
|
system-ui,
|
||||||
|
sans-serif;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Siffror står i kolumn. En beteckning jämförs oftare än den läses. */
|
||||||
|
.alva-yta {
|
||||||
|
font-variant-numeric: tabular-nums;
|
||||||
|
}
|
||||||
|
|
||||||
|
.alva-yta .font-mono {
|
||||||
|
font-family:
|
||||||
|
ui-monospace,
|
||||||
|
"IBM Plex Mono",
|
||||||
|
"SF Mono",
|
||||||
|
"Cascadia Mono",
|
||||||
|
Menlo,
|
||||||
|
Consolas,
|
||||||
|
"Liberation Mono",
|
||||||
|
monospace;
|
||||||
|
}
|
||||||
|
|
||||||
@layer utilities {
|
@layer utilities {
|
||||||
.animate-fade-up {
|
.animate-fade-up {
|
||||||
animation: fadeUp 0.8s ease-out forwards;
|
animation: fadeUp 0.8s ease-out forwards;
|
||||||
|
|||||||
@@ -28,7 +28,9 @@ export function Ram({ children, portal = false }: { children: ReactNode; portal?
|
|||||||
const lankar = portal ? PORTAL : PUBLIKT;
|
const lankar = portal ? PORTAL : PUBLIKT;
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="min-h-screen" style={{ background: FARG.background, color: FARG.graphite }}>
|
// `alva-yta` bär typografin ur ALVA-SPEC-001 och håller den skild
|
||||||
|
// från värdapplikationens antikva. Se src/index.css.
|
||||||
|
<div className="alva-yta min-h-screen" style={{ background: FARG.background, color: FARG.graphite }}>
|
||||||
<header className="border-b" style={{ borderColor: FARG.lightSteel, background: FARG.white }}>
|
<header className="border-b" style={{ borderColor: FARG.lightSteel, background: FARG.white }}>
|
||||||
<div className="mx-auto flex max-w-[1040px] flex-wrap items-center justify-between gap-4 px-6 py-4">
|
<div className="mx-auto flex max-w-[1040px] flex-wrap items-center justify-between gap-4 px-6 py-4">
|
||||||
<Link to={portal ? "/alva/portal" : "/alva"} className="flex items-baseline gap-4">
|
<Link to={portal ? "/alva/portal" : "/alva"} className="flex items-baseline gap-4">
|
||||||
|
|||||||
Reference in New Issue
Block a user