Files
Artista-Filmcamp/src/lib/review-format.ts
T
Nick SzaunigandClaude Opus 5.5 f74a08fa68 feat: Google-Rezensionen als eigener Abschnitt auf der Onepage
- ReviewsSection (Server Component) mit Durchschnitt, zugaenglichen
  Sternen, Initialen statt Profilbildern, relativer Zeit, Links zur
  Rezension und zum Maps-Eintrag sowie Hinweis "Rezensionen von Google"
- lange Texte optisch gekuerzt, "Weiterlesen" mit aria-expanded
- ohne Daten ausgeblendet; in Entwicklung/Staging ein Einrichtungshinweis
- Laden parallel zu loadPublicPage, Fehler blenden nur den Abschnitt aus
- Links aus der API-Antwort nur zu HTTPS-Google-Hosts (safeGoogleUrl)
- Linkstile und Browser-Oberflaechen (Scrollbar, Caret, Unterstreichung)

Co-Authored-By: Claude Opus 5.5 (1M context) <[email protected]>
2026-09-28 17:46:19 +02:00

40 lines
1.5 KiB
TypeScript
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
/**
* Anzeigehilfen fuer Google-Rezensionen. Reine Funktionen ohne
* Seiteneffekte, damit sie ohne Netzwerk testbar sind.
*/
/** Ab dieser Laenge wird eine Rezension zunaechst gekuerzt angezeigt. */
export const REVIEW_CLAMP_CHARS = 320;
/** Initialen statt Profilbild: bis zu zwei Buchstaben aus dem Anzeigenamen. */
export function initialsOf(name: string): string {
const letters = name
.trim()
.split(/\s+/)
.map((part) => Array.from(part.replace(/[^\p{L}\p{N}]/gu, ""))[0] ?? "")
.filter(Boolean);
if (letters.length === 0) return "?";
const pick = letters.length === 1 ? [letters[0]] : [letters[0], letters[letters.length - 1]];
return pick.join("").toLocaleUpperCase("de-DE");
}
/** "4,8" – Durchschnitt mit einer Nachkommastelle im deutschen Format. */
export function formatRating(rating: number): string {
return rating.toLocaleString("de-DE", { minimumFractionDigits: 1, maximumFractionDigits: 1 });
}
/** Zugaenglicher Text fuer eine Sternebewertung, z. B. "4 von 5 Sternen". */
export function starsLabel(rating: number): string {
const value = Number.isInteger(rating) ? String(rating) : formatRating(rating);
return `${value} von 5 Sternen`;
}
/** "1 Rezension" bzw. "12 Rezensionen". */
export function reviewCountLabel(count: number): string {
return `${count.toLocaleString("de-DE")} ${count === 1 ? "Rezension" : "Rezensionen"}`;
}
export function needsClamp(text: string): boolean {
return text.length > REVIEW_CLAMP_CHARS;
}