Polish home page: clamp tile teasers, balance hero heading, fix embed gap

This commit is contained in:
tleininger committed 2026-10-01 14:44:55 +02:00
1 parent c24ca16a41
commit 6e5a30607e
4 files changed
+44 -47

No files matched your search

+17 -2
View File
@@ -38,8 +38,10 @@
/* On the gradient everything is white: the global heading colour is a blue that
would vanish here. */
/* balance evens out the lines, so a short last word ("IGMH") never wraps alone. */
.hero h1 {
color: var(--color-on-header);
text-wrap: balance;
}
/* The intro is editor Markdown, rendered without scope attributes, so it is reached
@@ -289,14 +291,23 @@
align-self: start;
}
/* The teaser is a whole sentence; the tile cuts it visually after three lines,
so the tiles of a row keep a similar height whatever the editor wrote. The
-webkit- box is the form every current browser supports for line-clamp. */
.tile-text {
display: block;
display: -webkit-box;
-webkit-box-orient: vertical;
-webkit-line-clamp: 3;
line-clamp: 3;
overflow: hidden;
}
}
/* --- Embeds -------------------------------------------------------------------
The blocks the home page opts into (posts, events) sit side by side from desktop
width, so the start page shows both without a long scroll. One column below. */
width, so the start page shows both without a long scroll. One column below.
In the grid the blocks' own top margin no longer collapses with the margin of
the tiles above, so it is dropped there; otherwise the gap would be doubled. */
@media (min-width: 64rem) {
.home-embeds {
display: grid;
@@ -304,4 +315,8 @@
gap: var(--space-5);
align-items: start;
}
.home-embeds ::deep .embed {
margin-top: 0;
}
}
+15 -36
View File
@@ -84,18 +84,12 @@ public static partial class Markdown
/// short description on a home page tile.
/// </summary>
/// <param name="markdown">The editor's Markdown; may be <see langword="null"/>.</param>
/// <param name="maxLength">
/// The longest sentence kept as is; a longer one is cut at the last word
/// boundary before the limit and ends in <c>…</c>.
/// </param>
/// <returns>
/// The first sentence of the first top-level paragraph, with all Markdown
/// removed and whitespace collapsed, or an empty string when there is no such
/// paragraph (empty body, or only headings, lists and blocks).
/// removed, whitespace collapsed and a trailing colon dropped, or an empty
/// string when there is no such paragraph (empty body, or only headings, lists
/// and blocks).
/// </returns>
/// <exception cref="ArgumentOutOfRangeException">
/// <paramref name="maxLength"/> is zero or negative.
/// </exception>
/// <remarks>
/// Only top-level paragraphs count: a heading repeats the title, and the text in
/// a list or a <c>:::</c> block is rarely a sentence that describes the page.
@@ -106,6 +100,12 @@ public static partial class Markdown
/// longer abbreviation such as <c>bzw.</c> still does; that costs the rest
/// of a teaser, never the page.
/// </para>
/// <para>
/// A paragraph that leads into a list often ends in <c>:</c> without a
/// period; as a teaser the colon would point at a list that is not there.
/// The sentence is returned whole: a long one is cut by the tile's CSS,
/// which knows the space it has, not by a character count.
/// </para>
/// </remarks>
/// <example>
/// <code>
@@ -113,14 +113,12 @@ public static partial class Markdown
/// // "Wir sind sieben Eltern."
/// </code>
/// </example>
public static string FirstSentence(string? markdown, int maxLength = 140) =>
maxLength <= 0
? throw new ArgumentOutOfRangeException(nameof(maxLength), maxLength, "Must be positive.")
: string.IsNullOrWhiteSpace(markdown)
? ""
: Parse(markdown).OfType<ParagraphBlock>().FirstOrDefault()?.Inline is { } inline
? Shorten(UpToSentenceEnd(PlainText(inline)), maxLength)
: "";
public static string FirstSentence(string? markdown) =>
string.IsNullOrWhiteSpace(markdown)
? ""
: Parse(markdown).OfType<ParagraphBlock>().FirstOrDefault()?.Inline is { } inline
? UpToSentenceEnd(PlainText(inline)).TrimEnd(':', ' ')
: "";
/// <summary>
/// Parses Markdown with the site's pipeline, for callers that take the document
@@ -194,25 +192,6 @@ public static partial class Markdown
private static string UpToSentenceEnd(string text) =>
SentenceEnd().Match(text) is { Success: true } end ? text[..(end.Index + 1)] : text;
/// <summary>
/// Shortens a text to at most <paramref name="maxLength"/> characters plus an
/// ellipsis, cutting between words.
/// </summary>
/// <param name="text">Plain text.</param>
/// <param name="maxLength">The longest text kept as is.</param>
/// <returns>The text, shortened if needed.</returns>
/// <remarks>
/// The search for a space starts at <paramref name="maxLength"/> itself, so a
/// word that ends exactly at the limit is kept. A single word longer than the
/// limit is cut hard.
/// </remarks>
private static string Shorten(string text, int maxLength) =>
text.Length <= maxLength
? text
: text.LastIndexOf(' ', maxLength) is > 0 and var space
? $"{text[..space].TrimEnd(',', ';', ':', '-', '–')}…"
: $"{text[..maxLength]}…";
/// <summary>
/// Matches the end mark of a sentence: <c>.</c>, <c>!</c> or <c>?</c> before a
/// space or the end, unless it follows a lone letter (<c>z.</c>) or a number