< Summary

Line coverage
0%
Covered lines: 0
Uncovered lines: 54
Coverable lines: 54
Total lines: 160
Line coverage: 0%
Branch coverage
0%
Covered branches: 0
Total branches: 24
Branch coverage: 0%
Method coverage

Feature is only available for sponsors

Upgrade to PRO version

Metrics

File(s)

/home/runner/work/chronicis/chronicis/src/Chronicis.Client/Components/Shared/WikiLinkAutocomplete.razor

#LineLine coverage
 1@using Chronicis.Client.Services
 2
 3<div class="wiki-link-autocomplete"
 4     style="@GetPositionStyle()"
 05     @ref="_autocompleteElement">
 06
 07    @if (_autocompleteService.IsLoading)
 08    {
 09        <div class="wiki-link-loading">
 010            <MudProgressCircular Size="Size.Small" Indeterminate="true" Color="Color.Primary" />
 11            <div style="margin-top: 8px;">Searching...</div>
 12        </div>
 13    }
 014    else if (!_autocompleteService.Suggestions.Any())
 15    {
 16        <div class="wiki-link-no-results">
 017            @if (string.IsNullOrWhiteSpace(_autocompleteService.Query))
 18            {
 19                <text>Type to search...</text>
 20            }
 21            else
 22            {
 23                <text>No results found</text>
 24            }
 25        </div>
 26    }
 27    else
 28    {
 029        @for (int i = 0; i < _autocompleteService.Suggestions.Count; i++)
 30        {
 031            var index = i; // Capture for closure
 032            var suggestion = _autocompleteService.Suggestions[i];
 033            var isSelected = index == _autocompleteService.SelectedIndex;
 34
 35            <div class="wiki-link-suggestion @(isSelected ? "selected" : "")"
 036                 @onclick="() => HandleSuggestionClick(suggestion)"
 037                 @onmouseenter="() => HandleMouseEnter(index)">
 38
 39                <div class="wiki-link-suggestion-title">
 040                    @if (suggestion.IsExternal)
 41                    {
 042                        @if (suggestion.IsCategory)
 43                        {
 44                            <MudIcon Icon="@Icons.Material.Filled.Folder" Size="Size.Small" />
 45                        }
 46                        else
 47                        {
 48                            <MudIcon Icon="@Icons.Material.Filled.Link" Size="Size.Small" />
 49                        }
 050                        <span class="wiki-link-suggestion-badge">@suggestion.Tooltip</span>
 51                    }
 52                    else
 53                    {
 54                        <MudIcon Icon="@Icons.Material.Filled.Description" Size="Size.Small" />
 55                    }
 056                    @suggestion.DisplayText
 57                </div>
 58
 059                @if (!string.IsNullOrEmpty(suggestion.Tooltip) && !suggestion.IsExternal)
 60                {
 61                    <div class="wiki-link-suggestion-path">
 062                        @suggestion.Tooltip
 63                    </div>
 64                }
 65            </div>
 66        }
 67    }
 68</div>

/home/runner/work/chronicis/chronicis/src/Chronicis.Client/Components/Shared/WikiLinkAutocomplete.razor.cs

#LineLine coverage
 1using Chronicis.Client.Services;
 2using Microsoft.AspNetCore.Components;
 3
 4namespace Chronicis.Client.Components.Shared;
 5
 6public partial class WikiLinkAutocomplete : IDisposable
 7{
 08    [Inject] private IWikiLinkAutocompleteService _autocompleteService { get; set; } = null!;
 9
 010    [Parameter] public string EditorId { get; set; } = null!;
 011    [Parameter] public Guid? WorldId { get; set; }
 012    [Parameter] public EventCallback<WikiLinkAutocompleteItem> OnSuggestionSelected { get; set; }
 13
 14    private ElementReference _autocompleteElement;
 15
 16    protected override void OnInitialized()
 17    {
 18        // Subscribe to service events
 019        _autocompleteService.OnShow += HandleShow;
 020        _autocompleteService.OnHide += HandleHide;
 021        _autocompleteService.OnSuggestionsUpdated += HandleSuggestionsUpdated;
 022    }
 23
 24    private void HandleShow()
 25    {
 026        StateHasChanged();
 027    }
 28
 29    private void HandleHide()
 30    {
 031        StateHasChanged();
 032    }
 33
 34    private void HandleSuggestionsUpdated()
 35    {
 036        StateHasChanged();
 037    }
 38
 39    private string GetPositionStyle()
 40    {
 041        if (!_autocompleteService.IsVisible)
 42        {
 043            return "display: none;";
 44        }
 45
 046        var (x, y) = _autocompleteService.Position;
 047        return $"left: {x}px; top: {y}px;";
 48    }
 49
 50    private void HandleMouseEnter(int index)
 51    {
 52        // Update selected index when mouse hovers over an item
 53        // This syncs mouse and keyboard navigation
 054        _autocompleteService.SetSelectedIndex(index);
 055    }
 56
 57    private async Task HandleSuggestionClick(WikiLinkAutocompleteItem suggestion)
 58    {
 59        // Notify parent component of selection
 060        await OnSuggestionSelected.InvokeAsync(suggestion);
 61
 62        // Hide autocomplete
 063        _autocompleteService.Hide();
 064    }
 65
 66    private bool _disposed = false;
 67    public void Dispose()
 68    {
 69
 070        Dispose(true);
 71        // Suppress finalization, as cleanup has been done.
 072        GC.SuppressFinalize(this);
 073    }
 74
 75    protected virtual void Dispose(bool disposing)
 76    {
 077        if (_disposed)
 78        {
 079            return;
 80        }
 81
 082        if (disposing)
 83        {
 84            // Unsubscribe from events
 085            _autocompleteService.OnShow -= HandleShow;
 086            _autocompleteService.OnHide -= HandleHide;
 087            _autocompleteService.OnSuggestionsUpdated -= HandleSuggestionsUpdated;
 88        }
 89
 090        _disposed = true;
 091    }
 92}