The globe opens full screen; a phone held sideways keeps its feed
On a phone the globe is a banner above the feed; a tap on it now opens it full screen over everything, with a close button (Escape closes it too), the focus moving to that button and back, and the feed underneath kept as it was but out of reach (inert). The camera refits the new shape. Held sideways, a phone (a window at most 30rem tall, the new short: variant) has no room for the banner: the banner and its toggle give way to a button that opens the globe full screen. isMobileMedia, which picks the first visit's default, agrees with Tailwind's md now (it was off by one) and counts a phone held sideways. GlobePanel tells its state (data-globe-state). Phone flows: the globe opens full screen and closes, and a sideways phone keeps a feed at least 180px tall with no sideways scroll. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01LsXgEaXee4GCU1hwYgPJXw
This commit is contained in:
1 parent
8f15d0d5c1
commit
931b7fcff1
9 files changed
+139
-8
No files matched your search
@@ -30,7 +30,12 @@
|
||||
<NerdTip Heading="@Localizer["Feed"]" Rows="Stats" Placement="DTooltipPlacement.Bottom" Align="DTooltipAlign.End">
|
||||
<i class="ion-md-stats opacity-50" aria-label="@Localizer["Feed"]"></i>
|
||||
</NerdTip>
|
||||
<DButton Size="DSize.Sm" class="lg:hidden" Active="Filter.ShowGlobe" OnClick="ToggleGlobe" title="@Localizer["Globe"]">
|
||||
<DButton Size="DSize.Sm" class="lg:hidden max-lg:short:hidden" Active="Filter.ShowGlobe" OnClick="ToggleGlobe" title="@Localizer["Globe"]">
|
||||
<i class="ion-md-planet text-base"></i>
|
||||
</DButton>
|
||||
@* a phone held sideways has no room for the banner: the globe opens full screen *@
|
||||
<DButton Size="DSize.Sm" class="hidden max-lg:short:inline-flex" OnClick="() => OnGlobeFull.InvokeAsync()" title="@Localizer["Open the globe full screen"]"
|
||||
data-globe-full>
|
||||
<i class="ion-md-planet text-base"></i>
|
||||
</DButton>
|
||||
<DButton Size="DSize.Sm" class="hidden md:inline-flex" Active="IsComposing" OnClick="() => OnCompose.InvokeAsync()" title="@Localizer["Post"]">
|
||||
@@ -107,6 +112,8 @@
|
||||
[Parameter] public IEnumerable<NerdRow> Stats { get; set; } = [];
|
||||
[Parameter] public bool IsComposing { get; set; }
|
||||
[Parameter] public EventCallback OnCompose { get; set; }
|
||||
/// <summary>Opens the globe full screen (a phone held sideways, which has no room for its banner).</summary>
|
||||
[Parameter] public EventCallback OnGlobeFull { get; set; }
|
||||
/// <summary>Raised after Filter changed (tab, group or globe).</summary>
|
||||
[Parameter] public EventCallback<FeedFilter> OnChanged { get; set; }
|
||||
|
||||
|
||||
@@ -6,8 +6,10 @@
|
||||
was written. The posts' places go to the module in one call whenever they change; the module calls SunChanged when
|
||||
the Sun's moment changes. The top corner shows that moment, the phase of the day and the season (its tooltip the
|
||||
Sun's numbers); the bottom corner the camera and the frame rate, its tooltip the rest of the globe's numbers. The
|
||||
globe is isolated: its labels carry z-indexes by depth, which must not reach the corners' tooltips. *@
|
||||
<div class="relative w-full h-full">
|
||||
globe is isolated: its labels carry z-indexes by depth, which must not reach the corners' tooltips. Below lg the
|
||||
globe is a banner the page shows above the feed: a tap opens it full screen (Expanded, which the page lays out), and
|
||||
its close button or Escape brings the feed back. *@
|
||||
<div class="relative w-full h-full" tabindex="-1" @onkeydown="OnKeyDown" data-globe-state="@State">
|
||||
<div @ref="element" class="absolute inset-0 isolate" aria-label="@Localizer["Globe of the posts in view"]" role="img"></div>
|
||||
|
||||
@if (stats?.Sun is { } sun)
|
||||
@@ -33,6 +35,21 @@
|
||||
</div>
|
||||
}
|
||||
|
||||
@if (Expanded)
|
||||
{
|
||||
<button @ref="closeButton" type="button" class="btn btn-circle btn-sm absolute right-3 top-[max(0.75rem,env(safe-area-inset-top))] z-20"
|
||||
aria-label="@Localizer["Close"]" title="@Localizer["Close"]" @onclick="Close" data-globe-close>
|
||||
<i class="ion-md-close" aria-hidden="true"></i>
|
||||
</button>
|
||||
}
|
||||
else
|
||||
{
|
||||
<button @ref="expandButton" type="button" class="absolute inset-0 z-20 lg:hidden cursor-zoom-in" aria-label="@Localizer["Open the globe full screen"]"
|
||||
title="@Localizer["Open the globe full screen"]" @onclick="Open" data-globe-expand>
|
||||
<i class="ion-md-expand absolute right-3 bottom-3 text-lg rounded-full bg-base-100/70 p-1" aria-hidden="true"></i>
|
||||
</button>
|
||||
}
|
||||
|
||||
<div class="absolute left-2 bottom-2 z-10 flex items-center gap-2 text-[10px] font-mono opacity-70 pointer-events-auto">
|
||||
<NerdTip Heading="@Localizer["Globe"]" Rows="StatsRows()" Placement="DTooltipPlacement.Top" Align="DTooltipAlign.Start">
|
||||
<span class="badge badge-ghost badge-xs gap-1">
|
||||
@@ -61,6 +78,30 @@
|
||||
/// <summary>The id of the element that scrolls the feed's cards.</summary>
|
||||
[Parameter, EditorRequired] public string ScrollContainerId { get; set; }
|
||||
[Parameter] public List<FeedPost> Posts { get; set; } = [];
|
||||
/// <summary>Open full screen (a phone's banner tapped); the page lays the globe out over everything.</summary>
|
||||
[Parameter] public bool Expanded { get; set; }
|
||||
[Parameter] public EventCallback<bool> ExpandedChanged { get; set; }
|
||||
|
||||
ElementReference closeButton;
|
||||
ElementReference expandButton;
|
||||
bool focusClose;
|
||||
bool focusExpand;
|
||||
|
||||
string State => stats is null ? "loading" : stats.Error is { Length: > 0 } ? "error" : "live";
|
||||
|
||||
async Task Open()
|
||||
{
|
||||
focusClose = true;
|
||||
await ExpandedChanged.InvokeAsync(true);
|
||||
}
|
||||
|
||||
async Task Close()
|
||||
{
|
||||
focusExpand = true;
|
||||
await ExpandedChanged.InvokeAsync(false);
|
||||
}
|
||||
|
||||
Task OnKeyDown(KeyboardEventArgs e) => e.Key == "Escape" && Expanded ? Close() : Task.CompletedTask;
|
||||
|
||||
ElementReference element;
|
||||
IJSObjectReference module;
|
||||
@@ -78,6 +119,16 @@
|
||||
|
||||
protected override async Task OnAfterRenderAsync(bool firstRender)
|
||||
{
|
||||
if (focusClose && Expanded)
|
||||
{
|
||||
focusClose = false;
|
||||
await closeButton.FocusAsync();
|
||||
}
|
||||
if (focusExpand && !Expanded)
|
||||
{
|
||||
focusExpand = false;
|
||||
await expandButton.FocusAsync(preventScroll: true);
|
||||
}
|
||||
await base.OnAfterRenderAsync(firstRender);
|
||||
try
|
||||
{
|
||||
|
||||
Reference in new issue
Block a user