diff --git a/CHANGELOG.md b/CHANGELOG.md index 301c7e0..99c4502 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -8,6 +8,12 @@ The application version is maintained in `package.json` and displayed in the adm No changes recorded yet. +## 1.17.1 - 2026-09-11 + +### Changed + +- Updated the in-app Guide (sv/en) for everything shipped this session: the new race-day Schedule feature (new "Race day time schedule" section, plus an overview card), staggered-start car call-outs and the per-driver "Done" flag, the new Settings and Event Manager tab layouts, and the driver transponder-conflict warning. Also corrected an outdated line claiming Open/Free Practice was the only thing that skipped the start ceremony - a scheduled "Practice" session in a structured event now gets the full sequence too. + ## 1.17.0 - 2026-09-11 ### Changed diff --git a/ROADMAP.md b/ROADMAP.md index 46022a4..9f501b5 100644 --- a/ROADMAP.md +++ b/ROADMAP.md @@ -409,6 +409,19 @@ Requested 2026-09-11 by the user, alongside a Guide update, as the second of two Verified 2026-09-11 with a live headless-browser check against a real, isolated server: confirmed the Setup tab is shown by default with the other three hidden; clicking each tab shows that tab's own content (format's `generateQualifying` button, live's grid editor, schedule's form and print buttons) while hiding the others; confirmed session-plan and branding stay visible on every tab; confirmed a step-card jump to a Live-tab target both switches to that tab and makes the target actually visible (not just scrolled-to-while-hidden); confirmed the Open Grid button switches to the Live tab; and confirmed a sponsor/track-mode event's manager page renders with zero `.manage-tab` elements, i.e. its layout is untouched. The full existing browser regression suite (23 tests, including the sponsor-event and race-wizard flows that exercise this same page) was also re-run and passed unchanged. +## In-app Guide updated for this session's shipped features + +Requested 2026-09-11 by the user as the first of two "make it easier for a new, non-technical person to use RaceCore" asks (the second is the Event Manager tabs entry above). The Guide (`src/misc_views.js`) hadn't been touched since several features shipped earlier this session, so it no longer reflected reality. + +- [x] New "Race day time schedule" section (4 bullets) plus a matching overview card, documenting the new Schedule feature end to end: where to set it, how the cascade works, how it re-anchors to reality (including the "Delayed" flag), and that it prints on the start lists. +- [x] Two new bullets under Seeding/points tables/tie-break covering staggered start: each driver's own personal timing window and the green "Done" flag, and why the shared clock now extends for staggered heats. +- [x] A new bullet under Race sounds covering the staggered-start car call-out announcer, and a **correction** to an existing bullet that had gone stale this session - it previously said Open/Free Practice was the only thing that skipped the start ceremony, which stopped being true once "practice" sessions inside a structured event started getting the full sequence too. +- [x] A new bullet under Decoder roles noting Settings' new four-tab layout (Connection/Audio/Appearance & overlay/System & backup) and where the decoder settings documented in that section now live. +- [x] A new bullet under Manage race in four steps noting Event Manager's new tab layout, and a correction to the step-card bullet clarifying that clicking a card now switches tabs automatically, not just scrolls. +- [x] A new bullet under Race Day covering the driver transponder-conflict warning (added to Drivers earlier this session), framed as a complement to the existing preflight duplicate-transponder check it sits next to. + +Verified 2026-09-11 with a live headless-browser check in both languages: confirmed the new Schedule section and overview card render with the correct title/content, confirmed no raw untranslated `guide.*` keys leaked onto the page in either language, and spot-checked the new staggered-done-flag, Settings-tabs, and Event-Manager-tabs bullets are all present and correctly translated. + ## Documentation maintenance - [ ] Update the architecture's module/dependency inventory as modules change. diff --git a/package-lock.json b/package-lock.json index 572bd4a..413f0c6 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,12 +1,12 @@ { "name": "rc-racecore", - "version": "1.17.0", + "version": "1.17.1", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "rc-racecore", - "version": "1.17.0", + "version": "1.17.1", "hasInstallScript": true, "dependencies": { "better-sqlite3": "^12.11.1", diff --git a/package.json b/package.json index bce1e0c..f6ddf28 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "rc-racecore", - "version": "1.17.0", + "version": "1.17.1", "private": true, "description": "RC RaceCore live timing and race control with AMMC ingest and SQLite persistence", "engines": { diff --git a/src/app.js b/src/app.js index 55c62e1..80affe6 100644 --- a/src/app.js +++ b/src/app.js @@ -1045,7 +1045,14 @@ const TRANSLATIONS = { "events.detail_active": "aktiva", "guide.manage_steps_6": "6. Statusbrickorna visar om varje steg är klart, väntar eller behöver åtgärdas. Sammanfattningen till höger visar också varningar om deltagare, lag eller sessioner saknas.", "guide.manage_steps_7": "7. Klicka på en varning i sammanfattningen för att hoppa direkt till rätt sektion i Hantera i stället för att leta manuellt.", - "guide.manage_steps_8": "8. Stegkorten högst upp fungerar också som snabbhopp. Klicka på Setup, Format, Generering eller Live / resultat för att gå direkt till rätt block.", + "guide.manage_steps_8": "8. Stegkorten högst upp fungerar också som snabbhopp. Klicka på Setup, Format, Generering eller Live / resultat för att gå direkt till rätt block - de byter flik automatiskt om blocket ligger bakom en annan flik.", + "guide.manage_steps_9": "9. Hantera-sidan för race är uppdelad i fliken Deltagare & lag, Format, Live & resultat samt Schema & utskrift, i stället för en lång scroll. Track-/sponsorevent har kvar den enkla, oflikade layouten.", + "guide.schedule_title": "Tidsschema för racedagen", + "guide.card_schedule_blurb": "Sätt en starttid och en paus mellan sessioner, så räknas varje sessions klockslag ut automatiskt.", + "guide.schedule_1": "1. Öppna Hantera -> fliken Schema & utskrift för ett race-event. Sätt starttid och paus mellan sessioner (standard 3 minuter) och klicka Spara schema.", + "guide.schedule_2": "2. Varje sessions planerade klockslag räknas ut i körordning (practice, sedan kval, sedan finaler) utifrån starttiden, sessionens längd/efterlöp och pausen mellan sessioner.", + "guide.schedule_3": "3. Så fort en session faktiskt startar eller avslutas flyttas resten av schemat automatiskt fram till den verkliga tiden - en sen start eller en session som drar över (inklusive paus) skjuter resten av dagen framåt utan att du behöver räkna om manuellt. En session som startade mer än en minut sent märks \"Försenad\".", + "guide.schedule_4": "4. Det planerade klockslaget skrivs också ut på startlistorna (Skriv ut/PDF startlistor) så förare kan se när deras session ungefär börjar.", "guide.race_wizard_title": "Create Race Wizard", "guide.race_wizard_1": "1. Börja i Race Setup och använd wizarden när du skapar ett nytt race, i stället för att bygga allt direkt i Hantera.", "guide.race_wizard_2": "2. Steg 1 sätter namn, datum, klass och preset. Presetet fyller rimliga standardvärden innan du finjusterar något.", @@ -1696,11 +1703,12 @@ const TRANSLATIONS = { "guide.audio_1": "1. Öppna Inställningar -> Raceljud och utrop. Välj svenska eller engelska och ställ master-, effekt-, röst- och passing-volym.", "guide.audio_2": "2. Aktivera effekt och röst separat för varje event. Testknappen på raden provar exakt det eventet; saknade WAV-filer hoppas över eller använder passing-fallback.", "guide.audio_3": "3. Välj 0, 10, 30 eller 60 sekunders förstart. För race följer sedan Förare gör er redo, startfras, fem startljus, slumpad väntan och startton.", - "guide.audio_4": "4. Den officiella raceklockan startar i samma callback som starttonen. Open/Free Practice startar direkt utan race-sekvens.", + "guide.audio_4": "4. Den officiella raceklockan startar i samma callback som starttonen. Bara Quick Open Practice och fri träning startar direkt utan race-sekvens - en schemalagd \"Practice\"-session i ett race/sponsor-event får samma nedräkning, ljus och startton som kval/heat/final.", "guide.audio_5": "5. Under Tidtagning finns manuella knappar för Stopp på banan, Banan fri, Röd flagg, felaktig start och banvaktsvarning. Kritiska utrop avbryter lägre prioriterat tal.", "guide.audio_6": "6. Under Förare och Bilar kan du välja pass_01.wav till pass_08.wav. Om filen saknas används standardljudet; lägg egna korta filer i rc-race-sound-pack/sounds/effects/.", "guide.audio_7": "7. Personbästa, snabbaste varv, banrekord, ledarbyte, tidsvarningar, depå in/ut, finish och podium hämtas från befintliga timinghändelser.", "guide.audio_8": "8. Ljudet spelas i operatörens webbläsare. Klicka Testa före racet, kontrollera ljudutgången och håll Tidtagning-fliken öppen.", + "guide.audio_9": "9. Staggered start i ett kvalheat läser upp varje bils transpondernummer i startordning, cirka 3 sekunder mellan varje bil, direkt efter den vanliga starten - mass/position-start läser aldrig upp enskilda bilar.", "guide.sponsor_title": "Skapa Sponsor Event: 10 personer, 4 bilar", "guide.sponsor_1": "1. Lägg upp 4 bilar i sidan Bilar med unikt transponder-ID. Lägg gärna också in märke/modell i brandfältet.", "guide.sponsor_2": "2. Lägg upp 10 förare i sidan Förare. Du kan också spara team/märke i brandfältet och filtrera listan på det senare.", @@ -1769,6 +1777,8 @@ const TRANSLATIONS = { "guide.qualifying_3": "Kval-scoring kan kombinera poängläge med poängtabell: placeringstal, fallande efter fältstorlek eller IFMAR 10-9-8-7-6-5-4-3-2-1.", "guide.qualifying_4": "Tie-break i kvalrankingen kan avgöras på räknade rundor, bästa enskilda varv eller bästa runda/heatresultat.", "guide.qualifying_5": "Leaderboarden visar seedningsresultat i rätt format, till exempel 3/00:48.321, 3 avg 16.107 eller 3 con 00:49.005.", + "guide.qualifying_6": "Vid staggered start har varje förare sitt eget tidsfönster som börjar vid deras egen första varvpassering - och en grön \"Klar\"-flagga visas bredvid förarens namn i Tidtagning och overlays så fort deras fönster gått ut, även om heatet fortfarande pågår för andra.", + "guide.qualifying_7": "Heatets gemensamma klocka förlängs automatiskt för staggered start så att den täcker hela utropsschemat (antal förare minus ett, gånger sekunderna mellan varje bil) utöver den vanliga längden - annars skulle sista utropade föraren riskera att bli avbruten innan de hunnit köra sin fulla tid.", "guide.race_day_title": "Race Day och säker start", "guide.card_race_day_blurb": "Förkontroll, startlista, heat-kö, automatisk backup och fokuserad racedrift.", "guide.race_day_1": "1. Skapa race och sessioner i Race Setup. Öppna sedan Race Day från gruppen Start.", @@ -1778,6 +1788,7 @@ const TRANSLATIONS = { "guide.race_day_5": "5. Vid start synkas state till backend och en konsistent SQLite-backup skapas i data/backups innan den befintliga audio- och starttonssekvensen körs. De 30 senaste sparas.", "guide.race_day_6": "6. Använd Race Day för start, paus, fortsätt och avslut. Menyn visar server- och sparstatus separat från decodern. Vid sparfel: behåll fliken öppen och klicka Försök igen; väntande ändringar är inte bekräftat sparade på servern. Tidtagning, Domare och Overlay finns som direkta genvägar. Lokal restore kräver stoppad server och npm run backup:restore -- --confirm.", "guide.race_day_7": "7. Session replay i Tidtagning spelar upp sparade passeringar i ett isolerat testläge. Välj session, ladda och kör i 1x, 2x, 5x eller 10x utan att ändra originalresultat eller träningsstatistik.", + "guide.race_day_8": "8. Redan när du registrerar eller ändrar en förare under Förare varnar systemet om transpondern redan används av en annan förare (t.ex. i fel klass) och namnger vem - ett komplement till förkontrollens kontroll av dubbla transpondrar inom samma heat. Samma person som kör flera klasser med sin egen transponder flaggas aldrig.", "guide.dashboard_title": "Schemaavvikelse på Översikt", "guide.dashboard_1": "Översikt visar nu skillnaden mellan planerad tid och faktisk körtid för alla startade sessioner.", "guide.dashboard_2": "Planerad tid räknar sessionstid plus follow-up. Faktisk tid räknar verklig tid från start till stopp eller nuvarande tid om heatet fortfarande kör.", @@ -1880,6 +1891,7 @@ const TRANSLATIONS = { "guide.decoder_roles_12": "12. Exempel: backend 192.168.1.100, main-decoder .10, split .11, depå in .12 och depå ut .13. Decoder-IP-fälten får .10-.13; klientens WS-url använder alltid backend .100 med port 9000-9003.", "guide.decoder_roles_13": "13. Startordning: pinga decoders från backend, starta backend, starta Managed AMMC, kontrollera AMMC-loggen, använd serverns WS-url och anslut sedan i Tidtagning.", "guide.decoder_roles_14": "14. Funktionstest: Main ska öka varv, Split ska inte öka varv, Depå in ska visa I DEPÅ och Depå ut ska skapa ett tidtaget stopp. Komplett guide finns i docs/decoder-setup.sv.md.", + "guide.decoder_roles_15": "15. Inställningar är uppdelat i flikarna Anslutning (decoder + Managed AMMC), Ljud, Utseende & overlay och System & backup, i stället för en lång scroll - decoder-inställningarna ovan hittar du under Anslutning.", "guide.host_1": "1. AMMC körs alltid på samma maskin som backend körs på (`npm.cmd start` i Windows eller `npm start` i Linux).", "guide.host_2": "2. Om du bara surfar in från en laptop/webbläsare startas ingen process där. Webbläsaren styr bara backend via HTTP.", "guide.host_3": "3. Kör backend på Linux-servern -> Linux-binären används: `AMMC/linux_x86-64/ammc-amb`.", @@ -2577,7 +2589,14 @@ const TRANSLATIONS = { "events.detail_active": "active", "guide.manage_steps_6": "6. The status badges show whether each step is complete, pending, or needs action. The summary on the right also warns when participants, teams, or sessions are missing.", "guide.manage_steps_7": "7. Click a warning in the summary to jump straight to the matching Manage section instead of hunting for it manually.", - "guide.manage_steps_8": "8. The step cards at the top also work as quick jumps. Click Setup, Format, Generation or Live / results to move straight to the right block.", + "guide.manage_steps_8": "8. The step cards at the top also work as quick jumps. Click Setup, Format, Generation or Live / results to move straight to the right block - they switch tabs automatically if the block is behind a different tab.", + "guide.manage_steps_9": "9. The race Manage page is split into the Participants & teams, Format, Live & results and Schedule & print tabs instead of one long scroll. Track/sponsor events keep the simple, untabbed layout.", + "guide.schedule_title": "Race day time schedule", + "guide.card_schedule_blurb": "Set a start time and a gap between sessions, and every session's clock time is worked out automatically.", + "guide.schedule_1": "1. Open Manage -> the Schedule & print tab for a race event. Set a start time and the gap between sessions (default 3 minutes) and click Save schedule.", + "guide.schedule_2": "2. Every session's planned clock time is worked out in running order (practice, then qualifying, then finals) from the start time, each session's own duration/follow-up, and the gap between sessions.", + "guide.schedule_3": "3. As soon as a session actually starts or finishes, the rest of the schedule automatically shifts to match reality - a late start or a session that runs long (including any pause) pushes the rest of the day forward with no manual recalculation. A session that started more than a minute late is marked \"Delayed\".", + "guide.schedule_4": "4. The planned clock time is also printed on the start lists (Print/PDF start lists) so drivers can see roughly when their session begins.", "guide.race_wizard_title": "Create Race Wizard", "guide.race_wizard_1": "1. Start in Race Setup and use the wizard when creating a new race instead of building everything directly in Manage.", "guide.race_wizard_2": "2. Step 1 sets name, date, class and preset. The preset fills sensible defaults before you fine-tune anything.", @@ -3228,11 +3247,12 @@ const TRANSLATIONS = { "guide.audio_1": "1. Open Settings -> Race sounds and announcements. Select Swedish or English and set master, effects, voice, and passing volume.", "guide.audio_2": "2. Enable effect and voice separately for every event. Each row has an exact event test; missing WAV files are skipped or use the passing fallback.", "guide.audio_3": "3. Select a 0, 10, 30, or 60 second pre-start. A race then runs drivers stand by, the start phrase, five start lights, random wait, and start tone.", - "guide.audio_4": "4. The official race clock starts in the same callback as the start tone. Open/Free Practice starts immediately without the race sequence.", + "guide.audio_4": "4. The official race clock starts in the same callback as the start tone. Only Quick Open Practice and free practice start immediately without the race sequence - a scheduled \"Practice\" session inside a race/sponsor event gets the same countdown, lights, and start tone as qualifying/heat/final.", "guide.audio_5": "5. Timing provides manual controls for Track call, Track clear, Red flag, False start, and Marshal warning. Critical announcements interrupt lower-priority speech.", "guide.audio_6": "6. Drivers and Cars can select pass_01.wav through pass_08.wav. A missing file uses the default; add short custom files under rc-race-sound-pack/sounds/effects/.", "guide.audio_7": "7. Personal best, fastest lap, track record, leader changes, time warnings, pit entry/exit, finish, and podium reuse existing timing events.", "guide.audio_8": "8. Audio plays in the operator browser. Use Test before racing, verify the audio output, and keep the Timing tab open.", + "guide.audio_9": "9. A staggered start in a qualifying heat calls out each car's transponder number in grid order, about 3 seconds apart, right after the official start - a mass/position start never calls out individual cars.", "guide.sponsor_title": "Create Sponsor Event: 10 drivers, 4 cars", "guide.sponsor_1": "1. Add 4 cars in Cars with unique transponder IDs. You can also store brand/model in the brand field.", "guide.sponsor_2": "2. Add 10 drivers in Drivers. You can also store team/brand in the brand field and filter by it later.", @@ -3301,6 +3321,8 @@ const TRANSLATIONS = { "guide.qualifying_3": "Qualifying scoring can combine points mode with a points table: placement values, descending by field size or IFMAR 10-9-8-7-6-5-4-3-2-1.", "guide.qualifying_4": "Qualifying tie-break can now be resolved by counted rounds, best single lap or best round / heat result.", "guide.qualifying_5": "The leaderboard now shows seeded results in the correct format, for example 3/00:48.321, 3 avg 16.107 or 3 con 00:49.005.", + "guide.qualifying_6": "In a staggered start, each driver's own timing window begins at their own first lap crossing - and a green \"Done\" flag appears next to their name in Timing and overlays as soon as their window has elapsed, even while the heat is still running for others.", + "guide.qualifying_7": "The heat's shared clock automatically extends for a staggered start to cover the full call-out schedule (driver count minus one, times the seconds between each car) on top of the normal duration - otherwise the last-called driver could be cut off before their full time is up.", "guide.race_day_title": "Race Day and safe start", "guide.card_race_day_blurb": "Preflight, start list, heat queue, automatic backup, and focused race operation.", "guide.race_day_1": "1. Create the race and sessions in Race Setup, then open Race Day from the Start group.", @@ -3310,6 +3332,7 @@ const TRANSLATIONS = { "guide.race_day_5": "5. Starting synchronizes state to the backend and creates a consistent SQLite backup in data/backups before the existing audio and start-tone sequence runs. The latest 30 are retained.", "guide.race_day_6": "6. Use Race Day for start, pause, resume, and finish. The menu shows server/save status separately from the decoder. On save failure, keep the tab open and click Retry; pending changes are not confirmed saved on the server. Timing, Judging, and Overlay remain one click away. Local restore requires a stopped server and npm run backup:restore -- --confirm.", "guide.race_day_7": "7. Session replay in Timing replays saved passings in an isolated test mode. Select a session, load it, and run at 1x, 2x, 5x, or 10x without modifying source results or training statistics.", + "guide.race_day_8": "8. Already when you register or edit a driver under Drivers, the system warns if the transponder is already used by a different driver (e.g. in the wrong class) and names who - a complement to the preflight's duplicate-transponder check within a single heat. The same person racing multiple classes on their own transponder is never flagged.", "guide.dashboard_title": "Schedule drift on overview", "guide.dashboard_1": "Overview now shows the difference between planned time and actual elapsed time for all started sessions.", "guide.dashboard_2": "Planned time includes session duration plus follow-up. Actual time uses real time from start to stop, or the current time if the heat is still running.", @@ -3412,6 +3435,7 @@ const TRANSLATIONS = { "guide.decoder_roles_12": "12. Example: backend 192.168.1.100, main decoder .10, split .11, pit entry .12, and pit exit .13. Decoder host fields receive .10-.13; client WS URLs always use backend .100 with ports 9000-9003.", "guide.decoder_roles_13": "13. Start order: ping decoders from backend, start backend, start Managed AMMC, inspect the AMMC log, use server WS URLs, then connect in Timing.", "guide.decoder_roles_14": "14. Functional test: Main increments laps, Split does not, Pit entry shows IN PIT, and Pit exit creates a timed stop. See docs/decoder-setup.md for the complete guide.", + "guide.decoder_roles_15": "15. Settings is split into the Connection (decoder + Managed AMMC), Audio, Appearance & overlay and System & backup tabs instead of one long scroll - the decoder settings above are under Connection.", "guide.host_1": "1. AMMC always runs on the backend host (`npm.cmd start` on Windows or `npm start` on Linux).", "guide.host_2": "2. If you only browse from a laptop/browser, no process is started there. The browser only controls the backend over HTTP.", "guide.host_3": "3. Run the backend on Linux -> the Linux binary is used: `AMMC/linux_x86-64/ammc-amb`.", diff --git a/src/misc_views.js b/src/misc_views.js index f100a61..ccb3bb6 100644 --- a/src/misc_views.js +++ b/src/misc_views.js @@ -35,12 +35,13 @@ export function renderGuideView({ dom, t }) { ${renderGuideOverviewCard("guide.training_title", "guide.card_training_blurb", { t })} ${renderGuideOverviewCard("guide.archive_title", "guide.card_archive_blurb", { t })} ${renderGuideOverviewCard("guide.windows_title", "guide.card_decoder_blurb", { t })} + ${renderGuideOverviewCard("guide.schedule_title", "guide.card_schedule_blurb", { t })}
- ${renderGuidePanel("guide.race_day_title", ["guide.race_day_1", "guide.race_day_2", "guide.race_day_3", "guide.race_day_4", "guide.race_day_5", "guide.race_day_6", "guide.race_day_7"], "", { t })} + ${renderGuidePanel("guide.race_day_title", ["guide.race_day_1", "guide.race_day_2", "guide.race_day_3", "guide.race_day_4", "guide.race_day_5", "guide.race_day_6", "guide.race_day_7", "guide.race_day_8"], "", { t })}
@@ -50,7 +51,11 @@ export function renderGuideView({ dom, t }) {
${renderGuidePanel("guide.race_title", ["guide.race_1", "guide.race_2", "guide.race_3", "guide.race_4", "guide.race_4a", "guide.race_5", "guide.race_6", "guide.race_7", "guide.race_8", "guide.race_9", "guide.race_10"], "", { t })} - ${renderGuidePanel("guide.manage_steps_title", ["guide.manage_steps_1", "guide.manage_steps_2", "guide.manage_steps_3", "guide.manage_steps_4", "guide.manage_steps_5", "guide.manage_steps_6", "guide.manage_steps_7", "guide.manage_steps_8"], "", { t })} + ${renderGuidePanel("guide.manage_steps_title", ["guide.manage_steps_1", "guide.manage_steps_2", "guide.manage_steps_3", "guide.manage_steps_4", "guide.manage_steps_5", "guide.manage_steps_6", "guide.manage_steps_7", "guide.manage_steps_8", "guide.manage_steps_9"], "", { t })} +
+ +
+ ${renderGuidePanel("guide.schedule_title", ["guide.schedule_1", "guide.schedule_2", "guide.schedule_3", "guide.schedule_4"], "", { t })}
@@ -65,7 +70,7 @@ export function renderGuideView({ dom, t }) {
${renderGuidePanel("guide.team_title", ["guide.team_1", "guide.team_2", "guide.team_3", "guide.team_4", "guide.team_5", "guide.team_6"], "", { t })} - ${renderGuidePanel("guide.qualifying_title", ["guide.qualifying_1", "guide.qualifying_2", "guide.qualifying_3", "guide.qualifying_4", "guide.qualifying_5"], "", { t })} + ${renderGuidePanel("guide.qualifying_title", ["guide.qualifying_1", "guide.qualifying_2", "guide.qualifying_3", "guide.qualifying_4", "guide.qualifying_5", "guide.qualifying_6", "guide.qualifying_7"], "", { t })}
@@ -78,11 +83,11 @@ export function renderGuideView({ dom, t }) {
- ${renderGuidePanel("guide.audio_title", ["guide.audio_1", "guide.audio_2", "guide.audio_3", "guide.audio_4", "guide.audio_5", "guide.audio_6", "guide.audio_7", "guide.audio_8"], "", { t })} + ${renderGuidePanel("guide.audio_title", ["guide.audio_1", "guide.audio_2", "guide.audio_3", "guide.audio_4", "guide.audio_5", "guide.audio_6", "guide.audio_7", "guide.audio_8", "guide.audio_9"], "", { t })}
- ${renderGuidePanel("guide.decoder_roles_title", ["guide.decoder_roles_1", "guide.decoder_roles_2", "guide.decoder_roles_3", "guide.decoder_roles_4", "guide.decoder_roles_5", "guide.decoder_roles_6", "guide.decoder_roles_7", "guide.decoder_roles_8", "guide.decoder_roles_9", "guide.decoder_roles_10", "guide.decoder_roles_11", "guide.decoder_roles_12", "guide.decoder_roles_13", "guide.decoder_roles_14"], "", { t })} + ${renderGuidePanel("guide.decoder_roles_title", ["guide.decoder_roles_1", "guide.decoder_roles_2", "guide.decoder_roles_3", "guide.decoder_roles_4", "guide.decoder_roles_5", "guide.decoder_roles_6", "guide.decoder_roles_7", "guide.decoder_roles_8", "guide.decoder_roles_9", "guide.decoder_roles_10", "guide.decoder_roles_11", "guide.decoder_roles_12", "guide.decoder_roles_13", "guide.decoder_roles_14", "guide.decoder_roles_15"], "", { t })} ${renderGuidePanel("guide.host_title", ["guide.host_1", "guide.host_2", "guide.host_3", "guide.host_4", "guide.host_5", "guide.host_6", "guide.host_7", "guide.host_8"], "", { t })}