FocusView browser maximize (Closes #1577) (#1578)

This commit is contained in:
2026-07-03 18:40:15 +02:00
parent 49f45b6b76
commit a9ee0424f7
4 changed files with 109 additions and 5 deletions
@@ -0,0 +1,37 @@
<div class="browser-container @(this.IsMaximized ? "maximized" : string.Empty)">
<button class="browser-toggle-button"
title="@(this.IsMaximized ? "Restore" : "Expand to fullscreen")"
@onclick="this.ToggleMaximized"
@onclick:stopPropagation="true">
<FluentIcon Value="@(this.IsMaximized ?
(Microsoft.FluentUI.AspNetCore.Components.Icon)new Microsoft.FluentUI.AspNetCore.Components.Icons.Regular.Size16.ArrowMinimize() :
new Microsoft.FluentUI.AspNetCore.Components.Icons.Regular.Size16.ArrowMaximize())" />
</button>
<iframe sandbox="allow-scripts allow-same-origin allow-forms"
class="browser-frame"
src="@this.Source" />
</div>
@code {
[Parameter]
public string? Source { get; init; }
[Parameter]
public Action? OnMaximized { get; init; }
[Parameter]
public Action? OnRestore { get; init; }
private bool IsMaximized { get; set; }
private void ToggleMaximized()
{
this.IsMaximized = !this.IsMaximized;
if (this.IsMaximized)
{
this.OnMaximized?.Invoke();
}
else
{
this.OnRestore?.Invoke();
}
}
}
@@ -0,0 +1,38 @@
.browser-container {
position: relative;
display: flex;
flex: 1;
min-height: 0;
height: 100%;
width: 100%;
}
.browser-frame {
flex: 1;
height: 100%;
width: 100%;
margin: -2px;
border: none;
}
.browser-toggle-button {
position: absolute;
top: 4px;
right: 4px;
z-index: 1002;
display: inline-flex;
align-items: center;
justify-content: center;
width: 22px;
height: 22px;
padding: 0;
border: none;
border-radius: 50%;
cursor: pointer;
background: rgba(0, 0, 0, 0.45);
color: #fff;
}
.browser-toggle-button:hover {
background: var(--accent-fill-rest);
}
+18 -5
View File
@@ -45,11 +45,11 @@
</div>
<div class="focus-content">
<div class="grid-stack" @ref="this.gridElement"
<div class="grid-stack @(this.maximizedComponent is not null ? "has-maximized" : string.Empty)" @ref="this.gridElement"
style="--focus-cols: @this.ViewModel.GridColumns; --focus-rows: @this.ViewModel.GridRows;">
@foreach (var tile in this.ViewModel.VisibleTiles)
{
<div class="grid-stack-item"
<div class="grid-stack-item @(this.maximizedComponent == tile.Component ? "maximized" : string.Empty)"
@key="tile.Component"
data-component="@tile.Component"
gs-x="@(tile.Column - 1)"
@@ -93,6 +93,7 @@
private ElementReference gridElement;
private int lastSyncedVersion = -1;
private bool isAddDropdownOpen;
private FocusViewComponent? maximizedComponent;
protected override async Task OnAfterRenderAsync(bool firstRender)
{
@@ -138,14 +139,26 @@
private void EnterEditLayout()
{
this.isAddDropdownOpen = false;
this.maximizedComponent = null;
this.ViewModel.ToggleEditLayout();
}
private void ToggleAddDropdown() => this.isAddDropdownOpen = !this.isAddDropdownOpen;
private void SetMaximized(FocusViewComponent? component)
{
this.maximizedComponent = component;
this.StateHasChanged();
}
private async Task ToggleComponentAsync(FocusViewComponent component)
{
await this.SyncFromGridAsync();
if (this.maximizedComponent == component)
{
this.maximizedComponent = null;
}
this.ViewModel.ToggleTileVisibility(component);
}
@@ -181,9 +194,9 @@
OnBuildClicked="@this.ViewModel.OnBuildClicked"
OnLoadPlayerSingleBuildClicked="@this.ViewModel.OnPlayerSingleBuildClicked"
OnLoadPlayerTeamBuildClicked="@this.ViewModel.OnPlayerTeamBuildClicked" />,
FocusViewComponent.Browser => @<iframe sandbox="allow-scripts allow-same-origin allow-forms"
style="height: 100%; width: 100%; margin: -2px;"
src="@this.ViewModel.BrowserSource" />,
FocusViewComponent.Browser => @<BrowserComponent Source="@this.ViewModel.BrowserSource"
OnMaximized="@(() => this.SetMaximized(FocusViewComponent.Browser))"
OnRestore="@(() => this.SetMaximized(null))" />,
_ => @<text></text>
};
+16
View File
@@ -130,6 +130,22 @@
z-index: 1001;
}
/* A maximized tile (e.g. Browser) expands to cover the whole grid area, hiding its siblings.
GridStack positions tiles with inline transform/width/height, so !important is required to
override it here. */
.grid-stack-item.maximized {
position: absolute !important;
inset: 0 !important;
transform: none !important;
width: 100% !important;
height: 100% !important;
z-index: 1500;
}
.grid-stack.has-maximized > .grid-stack-item:not(.maximized) {
display: none;
}
/* Per-tile remove button (top-right) to hide a component while editing. */
.tile-remove-button {
position: absolute;