diff --git a/Components/Content.razor b/Components/Content.razor index 175830a..7828c01 100644 --- a/Components/Content.razor +++ b/Components/Content.razor @@ -325,6 +325,10 @@ @Localizer["Bookmark"] + + + @Localizer["Details"] + @if (status.Url is { Length: > 0 } url) { @@ -416,6 +420,29 @@ + @* a phone's way to the nerd stats the card's corners hold on hover, all in one sheet *@ + @if (isDetailsOpen) + { + + @Localizer["Details"] + + + + + @if (Post.Location is { Source: LocationSource.Cdn } detailsCdn) + { + + } + else if (Post.Location is not null) + { + + } + + + + + } @if (isReporting && status.Account is { } reported) { @@ -497,6 +524,7 @@ [Parameter] public FilterContext? FilterIn { get; set; } bool isReplying; + bool isDetailsOpen; bool isQuoting; bool isEditing; bool isActing; @@ -581,7 +609,7 @@ @foreach (var media in status.MediaAttachments) { - + @if ((status.Sensitive || IsBlurred) && !revealedMedia.Contains(media.Id)) { + @if (Heading is { Length: > 0 }) + { + @Heading + } + + @foreach (var row in Rows.Where(row => !string.IsNullOrEmpty(row.Value))) + { + @row.Label + @row.Value + } + + @if (Pending) + { + @Localizer["loading"]… + } + + +@code { + [Parameter] public string Heading { get; set; } + [Parameter] public IEnumerable Rows { get; set; } = []; + /// Shown under the rows while the stats being read on demand arrive. + [Parameter] public bool Pending { get; set; } + + protected override void OnInitialized() => IsLoading = false; +} diff --git a/Components/Nerd/NerdTip.razor b/Components/Nerd/NerdTip.razor index 8f10b56..f0e0914 100644 --- a/Components/Nerd/NerdTip.razor +++ b/Components/Nerd/NerdTip.razor @@ -1,10 +1,32 @@ @inherits LocalizableComponentBase -@* Nerd stats on hover or focus: a DTooltip whose content is a monospace list of label/value rows. OnOpen runs on the - first hover or focus, for stats read on demand (a post's provenance); rows with no value are left out. *@ - - @ChildContent - +@* Nerd stats on hover or focus: a DTooltip whose content is the rows (NerdRows). A touch screen has no hover, so there + a tap opens the same rows in a sheet from the bottom (TapOpens; not for a trigger that is a link itself, the + pictures). OnOpen runs on the first hover, focus or tap, for stats read on demand (a post's provenance). *@ +@if (TapOpens) +{ + @* (on touch the trigger is at least 44px: daisyUI's tooltip draws its arrow with ::after, so padding-free min sizes) *@ + + @ChildContent + +} +else +{ + + @ChildContent + +} +@if (isSheetOpen) +{ + + @Heading + + + + +} @code { [Parameter] public RenderFragment ChildContent { get; set; } @@ -16,8 +38,19 @@ [Parameter] public DTooltipPlacement Placement { get; set; } [Parameter] public DTooltipAlign Align { get; set; } [Parameter] public string Class { get; set; } + /// A tap opens the rows in a sheet where the screen has no hover. + [Parameter] public bool TapOpens { get; set; } = true; bool opened; + bool isSheetOpen; + + async Task Tap() + { + if (CascadingState.Status.CanHover()) + return; + isSheetOpen = true; + await Open(); + } protected override void OnInitialized() => IsLoading = false; @@ -29,21 +62,5 @@ await OnOpen.InvokeAsync(); } - RenderFragment Body => @ - @if (Heading is { Length: > 0 }) - { - @Heading - } - - @foreach (var row in Rows.Where(row => !string.IsNullOrEmpty(row.Value))) - { - @row.Label - @row.Value - } - - @if (Pending) - { - @Localizer["loading"]… - } - ; + RenderFragment Body => @; } diff --git a/Resources/AllStrings.it.resx b/Resources/AllStrings.it.resx index 89014ca..0137395 100644 --- a/Resources/AllStrings.it.resx +++ b/Resources/AllStrings.it.resx @@ -1856,4 +1856,7 @@ Feed + + Dettagli + diff --git a/Resources/AllStrings.resx b/Resources/AllStrings.resx index de4c92b..e1a785f 100644 --- a/Resources/AllStrings.resx +++ b/Resources/AllStrings.resx @@ -1856,4 +1856,7 @@ Feeds + + Details + diff --git a/Services/AppStatusService.cs b/Services/AppStatusService.cs index 125ab5f..8dcd26c 100644 --- a/Services/AppStatusService.cs +++ b/Services/AppStatusService.cs @@ -42,6 +42,9 @@ public class AppStatusService(IJSRuntime jsRuntime) public bool IsMobileMedia() => JsSyncRuntime.Invoke("isMobileMedia"); + // whether the pointer can hover (a mouse); a touch screen can't, so what shows on hover there opens on a tap + public bool CanHover() => JsSyncRuntime.Invoke("canHover"); + // a sideways-scrolling strip of tabs shows its selected tab public void RevealActive(ElementReference strip) => JsSyncRuntime.InvokeVoid("revealActive", strip); diff --git a/Styles/feed.css b/Styles/feed.css index 01dcae2..aee137a 100644 --- a/Styles/feed.css +++ b/Styles/feed.css @@ -62,13 +62,25 @@ padding-inline-start: 1.25rem; } - /* daisyUI's tooltip is a pill; a block of nerd stats needs the corners of a box. */ + /* daisyUI's tooltip is a pill; a block of nerd stats needs the corners of a box. Hidden, it takes no room (daisyUI + only makes it transparent, and one past a card's edge made a phone's feed scroll sideways), and on a touch screen + it never shows: a tap opens the rows in a sheet instead (NerdTip). */ .tooltip-content:has(> .nerd-stats) { border-radius: var(--radius-box); padding: 0.5rem 0.65rem; max-width: min(22rem, 90vw); } + .tooltip:not(:hover, :focus-within, .tooltip-open) > .tooltip-content:has(> .nerd-stats) { + display: none; + } + + @media (hover: none) { + .tooltip-content:has(> .nerd-stats) { + display: none; + } + } + .float-tooltip-kap { padding: 0 !important; background: transparent !important; diff --git a/wwwroot/main.js b/wwwroot/main.js index 97cd473..7db0b90 100644 --- a/wwwroot/main.js +++ b/wwwroot/main.js @@ -123,6 +123,15 @@ window.clearAppBadge = () => { window.logFromJs(e.message, "clearAppBadge") } } +window.canHover = () => { + try { + return window.matchMedia("(hover: hover)").matches + } catch (e) { + console.error(e) + window.logFromJs(e.message, "canHover") + return true + } +} // the selected tab of a sideways-scrolling strip, brought into its middle window.revealActive = strip => { try {
@Heading
@Localizer["loading"]…