refactor(ui/templates): drop row kebabs; double-click opens templates
The right-click context menu is now the single entry point for every per-row action — folders, templates, and composition leaves. Drop the ⋮ kebab buttons that duplicated the menu and the click-to-open behavior that was easy to trigger by accident while navigating the tree. Templates and composition slots open on double-click instead. - RenderNodeKebab removed entirely. - Selectable / SelectedKeyChanged / OnTreeNodeSelected dropped from the TreeView wiring — single-click no longer navigates. - New OpenTemplate(id) helper bound to @ondblclick on Template and Composition labels.
This commit is contained in:
@@ -83,9 +83,7 @@
|
||||
ChildrenSelector="n => n.Children"
|
||||
HasChildrenSelector="n => n.Kind != TmplNodeKind.Composition && n.Children.Count > 0"
|
||||
KeySelector="n => (object)n.Key"
|
||||
StorageKey="templates-tree"
|
||||
Selectable="true"
|
||||
SelectedKeyChanged="OnTreeNodeSelected">
|
||||
StorageKey="templates-tree">
|
||||
<NodeContent Context="node">
|
||||
@RenderNodeLabel(node)
|
||||
</NodeContent>
|
||||
@@ -234,6 +232,9 @@
|
||||
|
||||
private TreeView<TmplNode> _tree = default!;
|
||||
|
||||
private void OpenTemplate(int templateId) =>
|
||||
NavigationManager.NavigateTo($"/design/templates/{templateId}");
|
||||
|
||||
private RenderFragment RenderNodeLabel(TmplNode node) => __builder =>
|
||||
{
|
||||
switch (node.Kind)
|
||||
@@ -249,83 +250,23 @@
|
||||
<span class="badge rounded-pill bg-secondary-subtle text-secondary-emphasis">@node.Children.Count</span>
|
||||
</span>
|
||||
}
|
||||
@RenderNodeKebab(node)
|
||||
break;
|
||||
|
||||
case TmplNodeKind.Template:
|
||||
<span class="tv-glyph"><i class="bi bi-file-earmark-text"></i></span>
|
||||
<span class="tv-label @(node.Children.Count > 0 ? "fw-semibold" : "")"
|
||||
title="@node.Label">@node.Label</span>
|
||||
@RenderNodeKebab(node)
|
||||
title="@node.Label"
|
||||
@ondblclick="() => OpenTemplate(node.EntityId)">@node.Label</span>
|
||||
break;
|
||||
|
||||
case TmplNodeKind.Composition:
|
||||
<span class="tv-glyph"><i class="bi bi-arrow-return-right"></i></span>
|
||||
<span class="tv-label" title="@node.Label">@node.Label</span>
|
||||
@RenderNodeKebab(node)
|
||||
<span class="tv-label" title="@node.Label"
|
||||
@ondblclick="() => OpenTemplate(node.Composition!.ComposedTemplateId)">@node.Label</span>
|
||||
break;
|
||||
}
|
||||
};
|
||||
|
||||
private RenderFragment RenderNodeKebab(TmplNode node) => __builder =>
|
||||
{
|
||||
<span class="tv-kebab dropdown ms-auto" @onclick:stopPropagation="true">
|
||||
<button type="button"
|
||||
class="btn btn-link btn-sm p-0 px-1 text-secondary tv-kebab-toggle"
|
||||
data-bs-toggle="dropdown"
|
||||
aria-expanded="false"
|
||||
aria-label="@($"More actions for {node.Label}")">
|
||||
<i class="bi bi-three-dots-vertical"></i>
|
||||
</button>
|
||||
<ul class="dropdown-menu dropdown-menu-end">
|
||||
@switch (node.Kind)
|
||||
{
|
||||
case TmplNodeKind.Folder:
|
||||
<li><button class="dropdown-item" @onclick="() => OpenNewFolderDialog(node.EntityId)">New Folder</button></li>
|
||||
<li><button class="dropdown-item" @onclick='() => NavigationManager.NavigateTo($"/design/templates/create?folderId={node.EntityId}")'>New Template</button></li>
|
||||
<li><button class="dropdown-item" @onclick="() => OpenRenameFolderDialog(node.EntityId, node.Label)">Rename</button></li>
|
||||
<li><button class="dropdown-item" @onclick="() => OpenMoveFolderDialog(node.EntityId, node.Label)">Move to Folder…</button></li>
|
||||
<li><hr class="dropdown-divider" /></li>
|
||||
<li><button class="dropdown-item text-danger" @onclick="() => DeleteFolder(node.EntityId, node.Label)">Delete</button></li>
|
||||
break;
|
||||
|
||||
case TmplNodeKind.Template:
|
||||
<li><button class="dropdown-item" @onclick='() => NavigationManager.NavigateTo($"/design/templates/create?parentId={node.EntityId}")'>New Inheriting Template</button></li>
|
||||
<li><button class="dropdown-item" @onclick="() => OpenComposeDialog(node.Template!)">Compose into…</button></li>
|
||||
<li><button class="dropdown-item" @onclick="() => OpenMoveTemplateDialog(node.EntityId, node.Label)">Move to Folder…</button></li>
|
||||
<li><hr class="dropdown-divider" /></li>
|
||||
<li><button class="dropdown-item text-danger" @onclick="() => DeleteTemplate(node.Template!)">Delete</button></li>
|
||||
break;
|
||||
|
||||
case TmplNodeKind.Composition:
|
||||
<li><button class="dropdown-item" @onclick='() => NavigationManager.NavigateTo($"/design/templates/{node.Composition!.ComposedTemplateId}")'>Open composed template</button></li>
|
||||
<li><button class="dropdown-item" @onclick="() => RenameComposition(node.Composition!)">Rename…</button></li>
|
||||
<li><hr class="dropdown-divider" /></li>
|
||||
<li><button class="dropdown-item text-danger" @onclick="() => DeleteComposition(node.Composition!)">Delete</button></li>
|
||||
break;
|
||||
}
|
||||
</ul>
|
||||
</span>
|
||||
};
|
||||
|
||||
private void OnTreeNodeSelected(object? key)
|
||||
{
|
||||
if (key is not string s) return;
|
||||
if (s.StartsWith("t:") && int.TryParse(s[2..], out var tid))
|
||||
{
|
||||
NavigationManager.NavigateTo($"/design/templates/{tid}");
|
||||
}
|
||||
else if (s.StartsWith("c:") && int.TryParse(s[2..], out var cid))
|
||||
{
|
||||
var comp = _templates.SelectMany(t => t.Compositions).FirstOrDefault(c => c.Id == cid);
|
||||
if (comp != null)
|
||||
{
|
||||
NavigationManager.NavigateTo($"/design/templates/{comp.ComposedTemplateId}");
|
||||
}
|
||||
}
|
||||
// Folder selection is intentionally a no-op (use right-click for folder actions).
|
||||
}
|
||||
|
||||
private RenderFragment RenderNodeContextMenu(TmplNode node) => __builder =>
|
||||
{
|
||||
switch (node.Kind)
|
||||
|
||||
Reference in New Issue
Block a user