FootballDirectionPreview.razor

Preview panel for a football match UI. Renders three design variants (on-air, coach notes, matchday programme), each with a match view and a season-result view, plus toggles for language, long names and animation. Static mock data, commands only select a preview state.

Rough Code
@using Sandbox
@using Sandbox.UI
@using Socer
@using System
@using System.Linq
@inherits PanelComponent

<root class="fd-preview fd-@Variant @(Motion?"fd-motion":"") fd-view-@View" style="position:absolute;left:0;top:0;width:100%;height:100%;">
@if(Game is not null)
{
    <div class="fd-background"><FootballWorldPanel @ref="World" Game="@Game" style="position:absolute;left:0;top:0;width:100%;height:100%;" /></div>
    <div class="fd-controls">
        <label>@T("НАПРАВЛЕНИЯ SOCER","SOCER DIRECTIONS")</label>
        @for(int i=0;i<3;i++){var choice=i;<button class="@(Variant==i?"active":"")" onclick=@(()=>Choose(choice))>@Direction(i)</button>}
        <div class="fd-control-divider"></div>
        <button onclick=@(()=>ChangeView("match")) class="@(View=="match"?"active":"")">@T("Матч","Match")</button>
        <button onclick=@(()=>ChangeView("choice")) class="@(View=="choice"?"active":"")">@T("Выход в кубок","Cup entry")</button>
        <button onclick=@(()=>ChangeView("victory")) class="@(View=="victory"?"active":"")">@T("Победа","Victory")</button>
        <button onclick=@(()=>{Russian=!Russian;Revision++;})>@(Russian?"RU":"EN")</button>
        <button class="@(Stress?"active":"")" onclick=@(()=>{Stress=!Stress;Revision++;})>@T("Длинные имена","Long names")</button>
        <button class="@(Motion?"active":"")" onclick=@(()=>{Motion=!Motion;Revision++;})>@T("Анимация","Motion")</button>
    </div>
    @if(View=="match")
    {
        @if(Variant==0)
        {
            <div class="fd-air-bug fd-enter"><div class="fd-air-round">PREMIER / 14</div><div class="fd-air-score"><label class="fd-air-time">67:24</label><label class="fd-club">@Home</label><label class="fd-air-goals">2 : 1</label><label class="fd-club">@Away</label></div><div class="fd-air-live"><span></span><label>@T("ВТОРОЙ ТАЙМ","SECOND HALF")</label></div></div>
            <div class="fd-air-event fd-enter"><label class="fd-air-event-minute">67′</label><div><label class="fd-eyebrow">@T("У БРОВКИ","FROM THE TOUCHLINE")</label><label>@T("Соперник устал. Пора усилить давление.","Their legs are going. Time to press higher.")</label></div></div>
            <div class="fd-air-desk fd-enter"><div class="fd-air-identity"><label class="fd-air-symbol">N</label><div><label class="fd-eyebrow">@T("ВАШ КЛУБ","YOUR CLUB")</label><label>@Home</label></div></div><div class="fd-air-actions"><button class="fd-selected" onclick=@(()=>SelectCommand(0))><label class="fd-command-number">01</label><label>@T("Прессинг","Press")</label></button><button onclick=@(()=>SelectCommand(1))><label class="fd-command-number">02</label><label>@T("В атаку","Attack")</label></button><button onclick=@(()=>SelectCommand(2))><label class="fd-command-number">03</label><label>@T("Сберечь силы","Conserve")</label></button></div><div class="fd-air-changes"><label>@T("ЗАМЕНЫ","SUBSTITUTIONS")</label><button onclick=@(()=>SelectCommand(3))>↗ 3 / 5</button></div><label class="fd-speed">1×</label></div>
        }
        else if(Variant==1)
        {
            <div class="fd-coach-score fd-enter"><label>67:24</label><label class="fd-coach-score-name">@Home</label><label class="fd-coach-goals">2 — 1</label><label class="fd-coach-score-name">@Away</label><label class="fd-coach-period">II</label></div>
            <div class="fd-coach-clipboard fd-enter"><div class="fd-clip"></div><label class="fd-eyebrow">@T("РАБОЧАЯ ТЕТРАДЬ","TOUCHLINE NOTES")</label><label class="fd-coach-title">@T("Дожать.","Push on.")</label><label class="fd-coach-note">@T("Соперник устал. Пора усилить давление.","Their legs are going. Time to press higher.")</label><div class="fd-mini-pitch"><div class="fd-halfway"></div><div class="fd-centre"></div>@for(int j=0;j<11;j++){var player=j;<div class="fd-marker" style="@MarkerStyle(j)">@PlayerNumbers[j]</div>}</div><div class="fd-formation"><label>4–3–3</label><label>@T("СБАЛАНСИРОВАННО","BALANCED")</label></div><button class="fd-coach-command" onclick=@(()=>SelectCommand(0))><label>↗</label><label>@T("Поднять прессинг","Press higher")</label></button><button class="fd-coach-secondary" onclick=@(()=>SelectCommand(3))>@T("Замены · 3 / 5","Substitutions · 3 / 5")</button></div>
            <div class="fd-coach-bottom fd-enter"><label class="fd-coach-bookmark">N</label><label>@T("Тренер решает — команда исполняет","Your call. Their next move.")</label><button onclick=@(()=>SelectCommand(1))>@T("В атаку","Attack")</button><button onclick=@(()=>SelectCommand(2))>@T("Сберечь силы","Conserve")</button><label>1×</label></div>
        }
        else
        {
            <div class="fd-program-masthead fd-enter"><div><label class="fd-program-edition">@T("ФУТБОЛЬНЫЙ КЛУБ / СЕЗОН 05","FOOTBALL CLUB / SEASON 05")</label><label class="fd-program-wordmark">NORTH.</label></div><label class="fd-program-live">@T("ПРЯМОЙ ЭФИР","LIVE FROM THE GROUND")</label><div class="fd-program-score"><label>@Home</label><label class="fd-program-goals">2 : 1</label><label>@Away</label></div><label class="fd-program-clock">67:24</label></div>
            <div class="fd-program-note fd-enter"><label class="fd-program-number">67</label><label class="fd-program-kicker">@T("МИНУТА / ВТОРОЙ ТАЙМ","MINUTE / SECOND HALF")</label><label class="fd-program-headline">@T("Момент\nдля рывка.","A moment\nto push.")</label><label class="fd-program-copy">@T("Соперник устал. Пора усилить давление.","Their legs are going. Time to press higher.")</label><button class="fd-program-primary" onclick=@(()=>SelectCommand(0))>@T("ПРЕССИНГ ↗","PRESS ↗")</button><button class="fd-program-link" onclick=@(()=>SelectCommand(1))>@T("В атаку →","Attack →")</button><button class="fd-program-link" onclick=@(()=>SelectCommand(2))>@T("Сберечь силы →","Conserve →")</button></div>
            <div class="fd-program-footer fd-enter"><label>@T("ВАШ КЛУБ. ВАША ИСТОРИЯ.","YOUR CLUB. YOUR STORY.")</label><button onclick=@(()=>SelectCommand(3))>@T("ЗАМЕНЫ 3 / 5 →","SUBSTITUTIONS 3 / 5 →")</button><label>1×</label></div>
        }
        <div class="fd-command-feedback @(SelectedCommand>=0?"visible":"")">@CommandFeedback</div>
    }
    else
    {
        var victory=View=="victory";
        <div class="fd-choice-shade"></div>
        @if(Variant==0)
        {
            <div class="fd-air-choice fd-enter"><div class="fd-air-choice-banner"><span></span><label>@T(victory?"ФИНАЛЬНЫЙ СВИСТОК":"СЕЗОН ЗАВЕРШЁН",victory?"FINAL WHISTLE":"SEASON COMPLETE")</label></div><label class="fd-air-choice-heading">@T(victory?"ВЫ ВЫИГРАЛИ\nФИНАЛЬНЫЙ КУБОК":"ПОСЛЕДНИЙ КУБОК.\nВАШ СЛЕДУЮЩИЙ МАТЧ.",victory?"FINAL CUP\nCHAMPIONS":"ONE LAST CUP.\nYOUR NEXT CHAPTER.")</label><div class="fd-air-choice-score"><label>@Home</label><label>@(victory?"2 : 1":"#2")</label><label>@(victory?Away:T("ПРЕМЬЕР-ЛИГА","PREMIER LEAGUE"))</label></div><label class="fd-choice-copy">@T(victory?"От третьей лиги до главного трофея. История клуба завершена победой.":"Второе место в последней лиге открывает финальный кубок. Четвертьфинал, полуфинал, финал — и главный трофей ваш.",victory?"From the Third League to the greatest trophy. Your club's story ends with a win.":"Second place in the final league unlocks the Final Cup. Quarter-final, semi-final, final — your last three steps to the trophy.")</label><div class="fd-air-choice-bottom"><div><label>@T("ПРЕМЬЕР-ЛИГА","PREMIER LEAGUE")</label><label>@T("2 МЕСТО · 27 ОЧКОВ · 14 МАТЧЕЙ","2ND PLACE · 27 POINTS · 14 MATCHES")</label></div><button onclick=@(()=>PreviewAdvance())>@T(victory?"ИСТОРИЯ КЛУБА →":"ГОТОВИТЬ КОМАНДУ →",victory?"CLUB HISTORY →":"PREPARE YOUR XI →")</button></div></div>
        }
        else if(Variant==1)
        {
            <div class="fd-coach-choice fd-enter"><div class="fd-coach-paper"><label class="fd-eyebrow">@T(victory?"ЗАПИСЬ В ИСТОРИИ КЛУБА":"ИТОГИ СЕЗОНА / ЗАПИСЬ ТРЕНЕРА",victory?"A PAGE IN CLUB HISTORY":"SEASON REVIEW / COACH'S NOTES")</label><label class="fd-coach-choice-title">@T(victory?"Мы сделали\nэто.":"Ещё три\nматча.",victory?"We did\nit.":"Three games\nto go.")</label><label class="fd-coach-choice-intro">@Home</label><label class="fd-choice-copy">@T(victory?"Победа в финальном кубке. Весь путь от третьей лиги пройден.":"Второе место в Премьер-лиге даёт нам право сыграть в финальном кубке. Теперь важен каждый выбор в составе.",victory?"Final Cup champions. Every step from the Third League is complete.":"Second place in the Premier League earns us a place in the Final Cup. Every choice in the starting XI matters now.")</label><div class="fd-coach-results"><label>PREMIER</label><label>02 / 08</label><label>@T("27 ОЧКОВ","27 POINTS")</label></div><label class="fd-coach-handnote">@T(victory?"Эта команда войдёт в историю.":"Цель: закончить начатое.",victory?"A team worth remembering.":"The job: finish what we started.")</label></div><div class="fd-coach-route"><label class="fd-eyebrow">@T("ФИНАЛЬНЫЙ КУБОК","FINAL CUP")</label>@for(int k=0;k<3;k++){<div class="fd-route-stop"><span>@(k+1)</span><div><label>@Stage(k)</label><label>@T(k==0?"8 клубов":k==1?"4 клуба":"2 клуба",k==0?"8 clubs":k==1?"4 clubs":"2 clubs")</label></div><label>@(victory?"✓":"—")</label></div>}<button class="fd-coach-route-primary" onclick=@(()=>PreviewAdvance())>@T(victory?"К истории клуба →":"Выбрать состав →",victory?"Club history →":"Pick the starting XI →")</button><button class="fd-coach-secondary" onclick=@(()=>ChangeView("match"))>@T("Назад к матчу","Back to match")</button></div></div>
        }
        else
        {
            <div class="fd-program-choice fd-enter"><div class="fd-program-choice-mast"><label>NORTH.</label><label>@T("СПЕЦИАЛЬНЫЙ ВЫПУСК / СЕЗОН 05","SPECIAL EDITION / SEASON 05")</label></div><div class="fd-program-choice-columns"><div class="fd-program-story"><label class="fd-program-kicker">@T(victory?"ЧЕМПИОНЫ ФИНАЛЬНОГО КУБКА":"ПРЕМЬЕР-ЛИГА / ВТОРОЕ МЕСТО",victory?"FINAL CUP CHAMPIONS":"PREMIER LEAGUE / SECOND PLACE")</label><label class="fd-program-choice-title">@T(victory?"ИСТОРИЯ\nНАПИСАНА.":"ДО ГЛАВНОГО\nОСТАЛОСЬ\nТРИ МАТЧА.",victory?"HISTORY.\nMADE.":"THREE GAMES\nFROM\nEVERYTHING.")</label><label class="fd-program-choice-copy">@T(victory?"Весь путь — от первого состава до главного трофея. Эта победа навсегда останется в истории клуба.":"Лига пройдена. Место в финальном кубке завоёвано. Последняя глава решит, кто поднимет главный трофей.",victory?"From your first eleven to the greatest trophy. This win will stay in club history.":"The league is complete. A Final Cup place is ours. The last chapter decides who lifts the greatest trophy.")</label><label class="fd-program-byline">@Home · SOCER</label></div><div class="fd-program-ticket"><label class="fd-ticket-stub">@T(victory?"НАВСЕГДА В ИСТОРИИ":"ПРИГЛАШЕНИЕ В ФИНАЛЬНЫЙ КУБОК",victory?"ONE FOR THE HISTORY BOOKS":"FINAL CUP ADMISSION")</label><label class="fd-ticket-large">@(victory?"2:1":"02")</label><label class="fd-ticket-title">@T(victory?"ФИНАЛ":"МЕСТО В ЛИГЕ",victory?"THE FINAL":"LEAGUE POSITION")</label><div class="fd-ticket-perforation"></div><label class="fd-ticket-team">@Home</label><label class="fd-ticket-record">@T("27 очков / 14 матчей","27 points / 14 matches")</label><button onclick=@(()=>PreviewAdvance())>@T(victory?"История клуба ↗":"К финальному кубку ↗",victory?"Club history ↗":"To the Final Cup ↗")</button></div></div></div>
        }
    }
}
</root>

@code {
    public int Variant {get;set;}
    public string View {get;set;}="match";
    public bool Russian {get;set;}=true;
    public bool Stress {get;set;}
    public bool Motion {get;set;}=true;
    public int Revision {get;set;}
    public int SelectedCommand {get;set;}=-1;
    FootballWorldPanel World;
    MatchController cachedGame;
    MatchController Game=>cachedGame??=Scene.GetAllComponents<MatchController>().FirstOrDefault();
    string Home=>Stress?T("Северный Атлетический Футбольный Клуб","North Metropolitan Athletic Football Club"):"NORTH FC";
    string Away=>Stress?T("Риверсайд Юнайтед Академический Клуб","Riverside United Association Football Club"):"RIVERSIDE";
    string T(string ru,string en)=>Russian?ru:en;
    string Direction(int i)=>i==0?T("Эфир","On air"):i==1?T("Тренерская","Coach's notes"):T("Программа матча","Matchday programme");
    string Stage(int i)=>i==0?T("Четвертьфинал","Quarter-final"):i==1?T("Полуфинал","Semi-final"):T("Финал","Final");
    static readonly int[] PlayerNumbers={1,3,4,5,2,8,6,10,7,9,11};
    static readonly int[] PlayerX={50,17,39,61,83,24,50,76,15,50,85};
    static readonly int[] PlayerY={90,70,74,74,70,47,50,47,21,14,21};
    static string MarkerStyle(int i)=>$"left:{PlayerX[i]}%;top:{PlayerY[i]}%;";
    string CommandFeedback=>SelectedCommand switch{0=>T("ПРЕССИНГ · выбран в макете","PRESS · selected in preview"),1=>T("АТАКА · выбрана в макете","ATTACK · selected in preview"),2=>T("СБЕРЕЧЬ СИЛЫ · выбрано в макете","CONSERVE · selected in preview"),3=>T("ЗАМЕНЫ · выбраны в макете","SUBSTITUTIONS · selected in preview"),_=>""};
    void Choose(int choice){Variant=choice;Revision++;}
    void ChangeView(string view){View=view;SelectedCommand=-1;Revision++;}
    void SelectCommand(int command){SelectedCommand=command;Revision++;}
    void PreviewAdvance(){View="match";SelectedCommand=-1;Revision++;}
    protected override void OnTreeBuilt()
    {
        base.OnTreeBuilt();
        Panel.StyleSheet.Load("/FootballDirectionPreview.razor.scss");
    }
    protected override int BuildHash()=>HashCode.Combine(Variant,View,Russian,Stress,Motion,Revision);
}