fix(nav,schrift): nur eigene Features in der Leiste, Instrument Sans laden

Zwei Korrekturen aus dem Review.

1. Die Seitenleiste zeigte die komplette Software-Navigation nach. Falsch:
   Kontakte, Leads, Pipelines, Postfach, Termine und Einstellungen stehen dort
   bereits, der Prototyp verdoppelt sie nur. Jetzt stehen in der Leiste
   ausschließlich unsere beiden Features — Dashboard (eigenes Feature, hier
   nicht enthalten) und Analytics — plus die Bausteingalerie im sekundären
   Bereich, die zum Prototyp und nicht zum Produkt gehört.

2. Die Schrift stimmte nicht. Die Software nutzt Instrument Sans, selbst
   gehostet als variable Schrift. Der Prototyp lud Inter über next/font,
   während ui/theme.css für sämtliche Subframe-Typo-Token bereits
   'Instrument Sans' verlangte — die Schrift war aber nie geladen und fiel auf
   die Systemschrift zurück. Ergebnis waren zwei verschiedene Schriften auf
   einer Seite, keine davon die der Software.

   Jetzt liegen dieselben woff2-Dateien unter public/fonts/, mit denselben
   @font-face-Regeln und derselben Alias-Zuordnung für Komponenten, die noch
   direkt auf Inter verweisen. next/font entfällt.

Der Layout-Prüfer lief nach dem Schriftwechsel erneut durch: andere Metrik,
andere Textbreiten — weiterhin keine Kollisionen über 6 Seiten × 7 Breiten.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01QPeZNwSeU7qG3RRCwaxEZX
This commit is contained in:
dejanandClaude Opus 5 committed 2026-08-29 20:34:35 +02:00
1 parent e85ceb6f9d
commit aa86dfe44d
7 files changed
+98 -82

No files matched your search

+59 -1
View File
@@ -1,6 +1,64 @@
@import "tailwindcss";
@import "../ui/theme.css";
/*
* Schrift: Instrument Sans, selbst gehostet — identisch zur Software.
*
* Die Dateien stammen aus `apps/web/public/fonts/` von HiveGrid Cloud, damit
* Schriftschnitt und Metrik exakt übereinstimmen. Variable Schrift (400–700).
*
* Warum das nötig war: `ui/theme.css` verlangt für alle Subframe-Typo-Token
* bereits "Instrument Sans", die Schrift wurde aber nie geladen — und der
* Fließtext war zusätzlich auf Inter gesetzt. Ergebnis waren zwei verschiedene
* Schriften auf einer Seite, keine davon die der Software.
*/
@font-face {
font-family: "Instrument Sans";
font-style: normal;
font-weight: 400 700;
font-stretch: 100%;
font-display: swap;
src: url("/fonts/instrument-sans-latin.woff2") format("woff2");
unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA,
U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193,
U+2212, U+2215, U+FEFF, U+FFFD;
}
@font-face {
font-family: "Instrument Sans";
font-style: normal;
font-weight: 400 700;
font-stretch: 100%;
font-display: swap;
src: url("/fonts/instrument-sans-latin-ext.woff2") format("woff2");
unicode-range: U+0100-02BA, U+02BD-02C5, U+02C7-02CC, U+02CE-02D7,
U+02DD-02FF, U+0304, U+0308, U+0329, U+1D00-1DBF, U+1E00-1E9F, U+1EF2-1EFF,
U+2020, U+20A0-20AB, U+20AD-20C0, U+2113, U+2C60-2C7F, U+A720-A7FF;
}
/*
* Einige Subframe-Komponenten verweisen noch direkt auf Inter. Damit sie nicht
* auf die Systemschrift zurückfallen, zeigt der Name auf dieselbe Datei —
* so hält es die Software auch.
*/
@font-face {
font-family: "Inter";
font-style: normal;
font-weight: 400 700;
font-stretch: 100%;
font-display: swap;
src: url("/fonts/instrument-sans-latin.woff2") format("woff2");
unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA,
U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193,
U+2212, U+2215, U+FEFF, U+FFFD;
}
@theme {
--default-font-family: "Instrument Sans", ui-sans-serif, system-ui,
-apple-system, "Segoe UI", Roboto, Helvetica, Arial, sans-serif;
--font-inter: var(--default-font-family);
--font-sans: var(--default-font-family);
}
/*
* HiveGrid Analytics Dashboard
* ---------------------------------------------------------------
@@ -28,7 +86,7 @@
body {
background: var(--color-neutral-50, #fafafa);
color: var(--color-text-neutral-primary);
font-family: "Inter", system-ui, -apple-system, sans-serif;
font-family: var(--default-font-family);
font-variant-numeric: tabular-nums;
}
+1 -8
View File
@@ -1,15 +1,8 @@
import type { Metadata } from "next";
import { Inter } from "next/font/google";
import { AppShell } from "@/features/dashboard/components/layout/AppShell";
import { DashboardProviders } from "@/features/dashboard/context/DashboardProviders";
import "./globals.css";
const inter = Inter({
variable: "--font-inter",
subsets: ["latin"],
weight: ["400", "500", "600", "700"],
});
export const metadata: Metadata = {
title: "HiveGrid · Analytics Dashboard",
description:
@@ -20,7 +13,7 @@ export default function RootLayout({
children,
}: Readonly<{ children: React.ReactNode }>) {
return (
<html lang="de" className={`${inter.variable} h-full antialiased`}>
<html lang="de" className="h-full antialiased">
<body className="min-h-full">
<DashboardProviders>
<AppShell>{children}</AppShell>
+5 -1
View File
@@ -236,7 +236,11 @@ zwischen den Karten, zerfällt das Raster optisch.
| Label, Achsen, Legende | 12 px | 400–500 |
| Kleinstschrift (Meta) | 11 px | 400 |
Eine Schriftfamilie (Inter). Zahlen immer in Tabellenziffern
Eine Schriftfamilie: **Instrument Sans**, selbst gehostet aus denselben
Schriftdateien wie die Software (`public/fonts/`, variabel 400–700). Vorher lief
der Prototyp auf Inter, während `ui/theme.css` für alle Subframe-Typo-Token
bereits „Instrument Sans" verlangte — zwei Schriften auf einer Seite, keine
davon die der Software. Zahlen immer in Tabellenziffern
(`font-variant-numeric: tabular-nums`, global gesetzt), damit Spalten
untereinander stehen.
+13 -19
View File
@@ -2,27 +2,23 @@
## Struktur
Die Seitenleiste **spiegelt die von HiveGrid Cloud** — dieselbe Komponente
(`ui/components/SidebarWithSections`), dieselben Gruppen, dieselbe Reihenfolge:
Die Seitenleiste zeigt **nur unsere beiden Features**. Kontakte, Leads,
Pipelines, Postfach, Termine und Einstellungen stehen bereits in der
Seitenleiste der Software und werden hier nicht verdoppelt — der Prototyp zeigt,
was dazukommt, nicht was schon da ist.
```
HIVEGRID
├── Dashboard gehört zur Software, hier nicht enthalten
├── Analytics ◄── der Prototyp lebt hier /analytics
├── Aufgaben gehört zur Software
├── Kunden
│ ├── Kontakte · Leads
├── Projekte
│ ├── Pipelines · Plantafel · Dateien
├── Kommunikation
│ ├── Postfach · Formulare · Telefonie
├── Organisation
│ └── Termine
├── Dashboard eigenes Feature, nicht Teil dieses Prototyps
└── Analytics ◄── der Prototyp lebt hier /analytics
├─────────────────────
├── Komponenten Bausteingalerie des Prototyps /komponenten
└── Einstellungen gehört zur Software
└── Komponenten Bausteingalerie des Prototyps /komponenten
```
Gerendert wird mit derselben Komponente wie in der Software
(`ui/components/SidebarWithSections`, aus der Cloud-Fassung portiert) und
derselben Schrift (Instrument Sans, selbst gehostet aus denselben Dateien).
**Analytics ist ein einzelner Menüpunkt**, kein aufklappbarer Bereich. Die fünf
Analyse-Seiten sind darin über **Reiter** erreichbar:
@@ -39,10 +35,8 @@ Zwei Navigationsebenen für dieselbe Sache — Unterpunkte in der Seitenleiste
`SettingsHubShell.tsx` im Zielsystem: ein `Link` um ein `Tabs.Item`, damit jeder
Reiter eine echte Adresse hat und mittelklickbar bleibt.
**Nur Analytics und Komponenten führen hier irgendwohin.** Die übrigen Einträge
zeigen, wo die Analyse in der fertigen Anwendung sitzt, und melden beim Klick,
dass sie zur Software gehören. Eine tote Schaltfläche ohne Rückmeldung wäre
schlechter als gar keine.
„Dashboard" führt hier nirgendwohin und meldet das beim Klick — es ist ein
eigenes Feature, siehe [SCOPE-ANALYTICS-DASHBOARD.md](SCOPE-ANALYTICS-DASHBOARD.md).
---
@@ -1,21 +1,20 @@
import type { SeitenId } from "../../data/filtering";
/**
* Navigationsstruktur — Spiegel der Seitenleiste von HiveGrid Cloud.
* Navigationsstruktur des Prototyps.
*
* Die Gruppen, ihre Reihenfolge und die Einträge entsprechen
* `apps/web/app/application/sidebar/AppSidebar.tsx` im Zielsystem. Der Grund
* ist die Übergabe: Wer diesen Prototyp neben der Software öffnet, soll dieselbe
* Navigation sehen und nicht erst übersetzen müssen.
* Hier stehen **nur unsere beiden Features**: Dashboard und Analytics. Alles
* andere — Kontakte, Leads, Pipelines, Postfach, Termine, Einstellungen — ist
* in der Seitenleiste der Software bereits vorhanden und wird hier nicht
* verdoppelt. Der Prototyp zeigt, was dazukommt, nicht was schon da ist.
*
* **Nur „Analytics" ist in diesem Prototyp echt.** Alle anderen Einträge sind
* Kontext — sie zeigen, wo die Analyse in der fertigen Anwendung sitzt. Sie
* führen bewusst nirgendwohin und melden das beim Klick, statt still zu bleiben.
* Gerendert wird mit derselben Komponente wie in der Software
* (`ui/components/SidebarWithSections`, aus der Cloud-Fassung portiert), damit
* Aussehen und Verhalten übereinstimmen.
*
* Icons: Die Software nutzt eigene Icon-Komponenten (`AddressBookIcon`,
* `BoardIcon` …), die auf einem hausinternen Set aufsetzen. Hier stehen die
* nächstliegenden Feather-Icons aus `@subframe/core`, das beide Repos teilen —
* optisch praktisch deckungsgleich, ohne ein ganzes Icon-Set mitzuschleppen.
* „Dashboard" führt hier nirgendwohin: Es ist ein eigenes Feature und nicht
* Teil dieses Prototyps (siehe `docs/SCOPE-ANALYTICS-DASHBOARD.md`). Der
* Eintrag meldet das beim Klick, statt still zu bleiben.
*/
export type NavZiel = { art: "route"; href: string } | { art: "software" };
@@ -44,69 +43,37 @@ export const NAV_GRUPPEN: NavGruppe[] = [
titel: "",
eintraege: [
{
// Gehört zu uns, ist aber ein eigenes Feature und nicht Teil dieses
// Prototyps — siehe docs/SCOPE-ANALYTICS-DASHBOARD.md.
id: "dashboard",
label: "Dashboard",
icon: "LayoutDashboard",
ziel: { art: "software" },
},
{
// Der neue Menüpunkt. In der Software gibt es ihn noch nicht — die
// fünf Analyse-Seiten sind ausschließlich hier drin navigierbar,
// nicht als Unterpunkte in der Seitenleiste.
// Der neue Menüpunkt. Die fünf Analyse-Seiten sind ausschließlich hier
// drin über Reiter navigierbar, nicht als Unterpunkte in der Leiste.
id: "analytics",
label: "Analytics",
icon: "BarChart",
ziel: { art: "route", href: ANALYTICS_START },
},
{ id: "aufgaben", label: "Aufgaben", icon: "Clipboard", ziel: { art: "software" } },
],
},
{
id: "kunden",
titel: "Kunden",
eintraege: [
{ id: "kontakte", label: "Kontakte", icon: "Contact", ziel: { art: "software" } },
{ id: "leads", label: "Leads", icon: "TrendingUp", ziel: { art: "software" } },
],
},
{
id: "projekte",
titel: "Projekte",
eintraege: [
{ id: "pipelines", label: "Pipelines", icon: "Trello", ziel: { art: "software" } },
{ id: "plantafel", label: "Plantafel", icon: "CalendarRange", ziel: { art: "software" } },
{ id: "dateien", label: "Dateien", icon: "FileText", ziel: { art: "software" } },
],
},
{
id: "kommunikation",
titel: "Kommunikation",
eintraege: [
{ id: "postfach", label: "Postfach", icon: "Mail", ziel: { art: "software" } },
{ id: "formulare", label: "Formulare", icon: "Table", ziel: { art: "software" } },
{ id: "telefonie", label: "Telefonie", icon: "Phone", ziel: { art: "software" } },
],
},
{
id: "organisation",
titel: "Organisation",
eintraege: [
{ id: "termine", label: "Termine", icon: "CalendarDays", ziel: { art: "software" } },
],
},
];
/** Unterer Bereich, durch einen Trenner abgesetzt — wie in der Software. */
/**
* Unterer Bereich, durch einen Trenner abgesetzt — wie in der Software.
* Hier steht nur, was zum Prototyp gehört: die Bausteingalerie für die
* Entwicklung. Sie ist kein Produktfeature und wandert beim Einbau nicht mit.
*/
export const NAV_SEKUNDAER: NavEintrag[] = [
{
// Gehört nicht zur Software, sondern zum Prototyp: die Bausteingalerie
// für die Entwicklung.
id: "komponenten",
label: "Komponenten",
icon: "Component",
ziel: { art: "route", href: "/komponenten" },
},
{ id: "einstellungen", label: "Einstellungen", icon: "Settings", ziel: { art: "software" } },
];
/**
Binary file not shown.
Binary file not shown.