dashboards/HerdManager/pages/Help.ps1
|
$helpPage = New-UDPage -Name 'Help' -Url '/help' -Content { New-UDCard -Title 'Usage Guide' -Content { $moduleBase = (Get-Module PowerShellUniversal.Apps.HerdManager).ModuleBase $mdPath = Join-Path $moduleBase 'docs' 'UsageGuide.md' if (Test-Path $mdPath) { try { $md = Get-Content -Path $mdPath -Raw # Convert markdown to HTML for in-app rendering (some PS versions return an object with .Html) $mdInfo = ConvertFrom-Markdown -InputObject $md $html = if ($mdInfo.Html) { $mdInfo.Html } else { [string]$mdInfo } # Ensure heading elements have id attributes so fragment links can target them. # We slugify the heading text to produce stable ids (lowercase, hyphens, alphanumerics) and avoid duplicates. $ids = @{} $sb = New-Object System.Text.StringBuilder $pos = 0 $hRegex = [regex]::new('<h([1-6])([^>]*)>(.*?)</h\1>', [System.Text.RegularExpressions.RegexOptions]::Singleline -bor [System.Text.RegularExpressions.RegexOptions]::IgnoreCase) $hMatches = $hRegex.Matches($html) foreach ($m in $hMatches) { $start = $m.Index $len = $m.Length $level = $m.Groups[1].Value $attrs = $m.Groups[2].Value $inner = $m.Groups[3].Value # Append HTML before this heading $sb.Append($html.Substring($pos, $start - $pos)) | Out-Null $pos = $start + $len if ($attrs -match '\bid\s*=') { # Heading already has an id; leave it as-is $sb.Append($m.Value) | Out-Null } else { # Get plain text from inner HTML $text = [regex]::Replace($inner, '<[^>]+>', '') -replace '^[\s\r\n]+|[\s\r\n]+$','' $slug = $text.ToLowerInvariant() # Remove characters we don't want, keep letters, numbers, spaces, and hyphens $slug = [regex]::Replace($slug, '[^\p{L}\p{Nd}\s-]', '') $slug = [regex]::Replace($slug, '\s+', '-') $slug = [regex]::Replace($slug, '-+', '-') $slug = $slug.Trim('-') if ([string]::IsNullOrEmpty($slug)) { $slug = 'section' } $base = $slug $i = 1 while ($ids.ContainsKey($slug)) { $slug = "$base-$i"; $i++ } $ids[$slug] = $true $newTag = "<h$level id=`"$slug`"$attrs>$inner</h$level>" $sb.Append($newTag) | Out-Null } } $sb.Append($html.Substring($pos)) | Out-Null $html = $sb.ToString() # Replace fragment links (href="#..." or href="/help#...") with button elements that use data-toc-target # Buttons avoid triggering route navigation and let us handle scrolling in-page via a small script $pattern = @' <a\b[^>]*\bhref\s*=\s*["'][^"']*#([^"']+)["'][^>]*>(.*?)</a> '@ $replacement = @' <button class="toc-link" data-toc-target="$1" type="button" role="link" tabindex="0" style="background:none;border:none;color:#1a73e8;text-decoration:underline;cursor:pointer;padding:0;margin:0">$2</button> '@ $html = [regex]::Replace($html, $pattern, $replacement, [System.Text.RegularExpressions.RegexOptions]::Singleline -bor [System.Text.RegularExpressions.RegexOptions]::IgnoreCase) New-UDHtml -Markup $html # In-page delegated handler: listen for clicks on .toc-link and scroll to the matching heading id. # Also handle direct navigation via hashchange or initial page load hash. $script = @' <script> (function(){ function scrollHash(){ try{ var id = window.location.hash && window.location.hash.length>1 ? window.location.hash.substring(1) : null; if(!id) return; var t = document.getElementById(id); if(t){ t.scrollIntoView({behavior:'smooth', block:'start'}); } }catch(e){} } document.addEventListener('click', function(e){ var el = e.target; while(el && el !== document){ try{ if(el.matches && el.matches('.toc-link')){ e.preventDefault(); var id = el.getAttribute('data-toc-target'); if(id){ var t = document.getElementById(id); if(t){ t.scrollIntoView({behavior:'smooth', block:'start'}); try{ history.replaceState(null,'','#'+id); }catch(e){} } } return; } }catch(err){} el = el.parentNode; } }, true); window.addEventListener('hashchange', scrollHash, false); setTimeout(scrollHash, 250); })(); </script> '@ New-UDHtml -Markup $script } catch { New-UDTypography -Text "Unable to render Usage Guide: $($_.Exception.Message)" -Variant body1 New-UDLink -Text 'Open raw Usage Guide on GitHub' -Url 'https://github.com/steviecoaster/HerdManager/blob/main/Usage%20Guide.md' } } else { New-UDTypography -Text 'Usage Guide not found in module.' -Variant body1 New-UDLink -Text 'Open the Usage Guide on GitHub' -Url 'https://github.com/steviecoaster/HerdManager/blob/main/Usage%20Guide.md' } } } |