diff --git a/2026/qual_config.js b/2026/qual_config.js new file mode 100644 index 000000000..65188ff66 --- /dev/null +++ b/2026/qual_config.js @@ -0,0 +1,59 @@ +var qualitativeConfig = ` +{ + "title": "Qualitative Scouting", + "page_title": "Robot Behavior", + "dataFormat": "tsv", + "checkboxAs": "10", + "prematch": { + "title": "Pre-Match", + "fields": [ + { "name": "Scouter", "code": "s", "type": "text", "size": 10, "maxSize": 20, "subtype": "scouter" }, + { "name": "Event", "code": "e", "type": "text", "size": 10, "maxSize": 20, "subtype": "event", "defaultValue": "2026TXHOU", "disabled": "true" }, + { "name": "Match", "code": "m", "type": "number", "size": 3, "maxSize": 3 }, + { "name": "Team #", "code": "t", "type": "number", "size": 5, "maxSize": 5 } + ] + }, + "sections": [ + { + "title": "Robot Behavior", + "fields": [ + { + "name": "Driving Style", + "code": "ds", + "type": "radio", + "choices": { "ag": "Aggressive", "def": "Defensive", "cau": "Cautious", "oth": "Other" } + }, + { + "name": "Defense Quality", + "code": "dq", + "type": "radio", + "choices": { "ex": "Excellent", "gd": "Good", "fa": "Fair", "po": "Poor", "na": "N/A" } + }, + { + "name": "Recovery from Faults", + "code": "rf", + "type": "radio", + "choices": { "qu": "Quick", "sl": "Slow", "no": "No Recovery" } + }, + { + "name": "Plays Well with Alliance", + "code": "pa", + "type": "checkbox" + }, + { + "name": "Frequently Disabled/Tipped", + "code": "fd", + "type": "checkbox" + }, + { + "name": "Notes", + "code": "n", + "type": "text", + "size": 40, + "maxSize": 200 + } + ] + } + ] +} +`; \ No newline at end of file diff --git a/pit.html b/pit.html index 11afb3a97..de662c1c2 100644 --- a/pit.html +++ b/pit.html @@ -1,63 +1,63 @@ - - - - - Scouting PASS - - - - - - - - - - - -
-
-
-

PWNAGE
Scouting PASS

-

Pit Scouting

-

- - -
-

-
- -
-

PWnAGE
Scouting PASS

-

Generate QR Code

-

-

- - -
  -
- -
-
 
  -
-

-
-
 
-

-

-
- -
-
- -
-
-
-
- -
- - - + + + + + Scouting PASS + + + + + + + + + + + +
+
+
+

PWNAGE
Scouting PASS

+

Pit Scouting

+

+ + +
+

+
+ +
+

PWnAGE
Scouting PASS

+

Generate QR Code

+

+

+ + +
  +
+ +
+
 
  +
+

+
+
 
+

+

+
+ +
+
+ +
+
+
+
+ +
+ + + diff --git a/qual.html b/qual.html new file mode 100644 index 000000000..7d1bcdf83 --- /dev/null +++ b/qual.html @@ -0,0 +1,436 @@ + + + + + Scouting PASS + + + + + + + + + + +
+
+ + +
+

Golden Gate Robotics

+

Qualitative Scouting

+

+ + + + + + + + + + + + + + + + + + + + +
Scouter
Event Code
Match #
+ +
+ + + +

+
+ + +
+

Golden Gate Robotics

+

Tier & Ranking

+

+ + +

+ + +
+

Assign each team a tier. If 2+ teams share a tier, drag to rank them against each other (optional).

+
+
+

+ + +

+
+ + +
+

Golden Gate Robotics

+

Generate QR Code

+

+

+ + + + + + + + + + + +
 
 
 
 
+

+

+ + +

+
+ +
+
+ +
+
+
+ +
+
+ + + + + diff --git a/resources/css/scoutingPASS.css b/resources/css/scoutingPASS.css index a1cb449c0..544786d11 100644 --- a/resources/css/scoutingPASS.css +++ b/resources/css/scoutingPASS.css @@ -1,359 +1,508 @@ -/* @font-face { - font-family: 'Roboto'; - src: url('./fonts/Roboto-Regular.ttf') format('truetype'); - font-weight: 400; - font-style: normal; - font-display: swap; -} -*/ - -html, body{ - height: 100%; - width: 100%; - margin: 0; - padding: 0; - color: white; - background-color: black; - font-family: Roboto, sans-serif; -} - -#prematch_table, #postmatch_table { - - font-family : Roboto, Oxygen, Ubuntu, Cantarell, 'Open Sans', 'Helvetica Neue', sans-serif !important; - text-align: center; - color: white; - font-size: 13px; - font-style: bold; - font-weight: 700; - letter-spacing: 1px; - border-width: 4px; - border-color: white; -} - -#auton_table, #endgame_table, #teleop_table { - font-family : Roboto, Oxygen, Ubuntu, Cantarell, 'Open Sans', 'Helvetica Neue', sans-serif !important; - color: black; - font-size: 13px; - font-style: bold; - font-weight: 700; - letter-spacing: 1px; - border-width: 4px; - border-color: black; -} - - -.button { - font-family: Roboto; - font-size: 16px; - font-weight: 500; -} - -.counter-button { - width: 40px; - height: 40px; - font-size: 14px; - padding: 5px; - border-radius: 4px; - background-color: #f6faff; - color: black; - border: black; - border-width: 1px; - border-style: solid; - cursor: pointer; - - display: flex; - justify-content: center; - align-items: center; -} - -/* hide the actual radio input */ -.radio-btn input[type="radio"] { - display: none; -} - -.radio-btn span { - display: inline-block; - padding: 6px 12px; /* size of the box */ - margin: 2px; /* spacing between buttons */ - border: 1px solid #444; /* box border */ - border-radius: 4px; /* rounded corners */ - cursor: pointer; - user-select: none; - text-align: center; -} - -/* highlight when selected */ -.radio-btn input[type="radio"]:checked + span { - background-color: rgb(239, 239, 236); - color: black; -} - -.radio-btn input[type="radio"][value^="r"] + span { - border-color: #d9534f; - border-style: solid; - border-width: 1px; - color: white; -} - -.radio-btn input[type="radio"][value^="b"] + span { - border-color: #0275d8; - border-style: solid; - border-width: 1px; - color: white; -} - -.radio-btn input[type="radio"][value^="r"]:checked + span { - background-color: #d9534f; - border-color: #d9534f; - border-style: solid; - border-width: 5px; - color: white; -} - -.radio-btn input[type="radio"][value^="b"]:checked + span { - background-color: #0275d8; - border-color: #0275d8; - border-style: solid; - border-width: 5px; - color: white; -} - -/* Style the label to look like a button */ -.check-btn { - display: inline-block; - padding: 15px 15px; - margin: 5px; - border-radius: 4px; - border-color: black; - border-style: solid; - border-width: 1px; - cursor: pointer; - color: white; - text-align: center; - user-select: none; /* Disable text selection */ -} - -@media (max-width: 768px) { - .check-btn { - padding: 4vw 6vw; /* Adjust padding for mobile */ - } -} - -/* Ensure no default checkbox styles */ -input[type="checkbox"] { - display: none; /* Hide the checkbox, it will be visually represented by the label */ -} - -#autonHeader, #endgameHeader, #teleopHeader1, #teleopHeader2{ - color: black; - border-color: black; - border-width: 4px; -} - -#postmatchHeader{ - border-width: 4px; - border-color: white; -} - -#prematchHeader1, #prematchHeader2{ - color: white; - border-color: white; - border-width: 4px; -} - -#qrHeader1, #qrHeader2 { - color: black; -} - -.field-image { - margin: 2vw; -} - -.field-image-src { - width: 225px; - max-width: 500px; - height: auto; - background-position: center; - border: 1px solid; -} - -.main-panel{ - display: none; - height: 100%; - min-height: 100%; - width: 100vw; - position: absolute; - left: 0; - top: 0; - color: white; - background-color: black; - font-family : Roboto, Oxygen, Ubuntu, Cantarell, 'Open Sans', 'Helvetica Neue', sans-serif !important; - text-align: justify; -} - -#prematch{ - display: table; -} - -#auton{ -} - -#teleop{ -} - -#endgame{ -} - -#postmatch{ -} - -#qr-code{ - text-align: center; - color: black; -} - -h1{ - font-family: Roboto; - text-align: center; - border-style: groove; - border-color: white; - border-width: 2px; - font-size: 40px; - padding: 10px; - font-weight: 500; -} - -#page2, #page4 { - color: black; -} - -h2{ - font-family: Roboto; - text-align: center; - font-size: 30px; - font-weight: 400; - font-style: italic; -} - -.match-label{ - text-align: center; -} - -.half-button-l{ - width: 48%; - margin: 1vw; - height: 100%; - font: roboto; -} - -.half-button-r{ - flex-grow: 1; - height: 100%; - width: 48%; - margin: 1vw; - font: roboto; -} - -.half-button-container{ - display: flex; -} - -#nextButton1, #nextButton2, #nextButton9, #nextButton10, .clearForm, .submitForm, #displayButton, #copyButton { - font-family: Roboto; - font-weight: 500; - padding: 10px; - background-color: rgb(151, 199, 240); - text-decoration: none; - display: inline-block; -} - -#nextButton3, #nextButton4, #nextButton5, #nextButton6, #nextButton7, #nextButton8 { - font-family: Roboto; - font-weight: 500; - background-color: black; - padding: 10px; - color: white; -} - -.undoButton, .flipButton { - font-family: Roboto; - font-weight: 500; - background-color: black; - padding: 10px; - color: white; - margin-left: 20px; -} - -#prevButton7, #prevButton8, #prevButton9{ - font-family: Roboto; - font-weight: 500; - background-color: rgb(151, 199, 240); - padding: 10px; -} - -#prevButton1, #prevButton2, #prevButton3, #prevButton4, #prevButton5, #prevButton6{ - font-family: Roboto; - font-weight: 500; - background-color: black; - padding: 10px; - color: white; - -} - -#prematch_table{ - font: Roboto; - font-weight: 500; - text-align: center; -} - - -h1 .odd { - font-family: Roboto; - font-weight: 500; - text-align: center; - color: #0AB4EC; -} - -h1 .even { - font-family: Roboto; - font-weight: 500; - text-align: center; - color: #42B333; -} - -table { - border: 1px solid black; - width: 100%; -} - -td { - padding: 10px 4px; -} - -input { - font-size: 16px; - font: roboto; - color: black; - background-color: white; -} - -.title { - width: "50%"; - text-align: right; -} - -.field { - width: "50%"; - text-align: left; -} - -#qr-table { - text-align: center; - color: black; - background-color: white; -} - -#data { - font-family:'Lucida Console', 'monospace'; - text-align: justify; -} +/* @font-face { + font-family: 'Roboto'; + src: url('./fonts/Roboto-Regular.ttf') format('truetype'); + font-weight: 400; + font-style: normal; + font-display: swap; +} +*/ + +html, body{ + height: 100%; + width: 100%; + margin: 0; + padding: 0; + color: white; + background-color: black; + font-family: Roboto, sans-serif; +} + +#prematch_table, #postmatch_table { + + font-family : Roboto, Oxygen, Ubuntu, Cantarell, 'Open Sans', 'Helvetica Neue', sans-serif !important; + text-align: center; + color: white; + font-size: 13px; + font-style: bold; + font-weight: 700; + letter-spacing: 1px; + border-width: 4px; + border-color: white; +} + +#auton_table, #endgame_table, #teleop_table { + font-family : Roboto, Oxygen, Ubuntu, Cantarell, 'Open Sans', 'Helvetica Neue', sans-serif !important; + color: black; + font-size: 13px; + font-style: bold; + font-weight: 700; + letter-spacing: 1px; + border-width: 4px; + border-color: black; +} + + +.button { + font-family: Roboto; + font-size: 16px; + font-weight: 500; +} + +.counter-button { + width: 40px; + height: 40px; + font-size: 14px; + padding: 5px; + border-radius: 4px; + background-color: #f6faff; + color: black; + border: black; + border-width: 1px; + border-style: solid; + cursor: pointer; + + display: flex; + justify-content: center; + align-items: center; +} + +/* hide the actual radio input */ +.radio-btn input[type="radio"] { + display: none; +} + +.radio-btn span { + display: inline-block; + padding: 6px 12px; /* size of the box */ + margin: 2px; /* spacing between buttons */ + border: 1px solid #444; /* box border */ + border-radius: 4px; /* rounded corners */ + cursor: pointer; + user-select: none; + text-align: center; +} + +/* highlight when selected */ +.radio-btn input[type="radio"]:checked + span { + background-color: rgb(239, 239, 236); + color: black; +} + +.radio-btn input[type="radio"][value^="r"] + span { + border-color: #d9534f; + border-style: solid; + border-width: 1px; + color: white; +} + +.radio-btn input[type="radio"][value^="b"] + span { + border-color: #0275d8; + border-style: solid; + border-width: 1px; + color: white; +} + +.radio-btn input[type="radio"][value^="r"]:checked + span { + background-color: #d9534f; + border-color: #d9534f; + border-style: solid; + border-width: 5px; + color: white; +} + +.radio-btn input[type="radio"][value^="b"]:checked + span { + background-color: #0275d8; + border-color: #0275d8; + border-style: solid; + border-width: 5px; + color: white; +} + +/* Style the label to look like a button */ +.check-btn { + display: inline-block; + padding: 15px 15px; + margin: 5px; + border-radius: 4px; + border-color: black; + border-style: solid; + border-width: 1px; + cursor: pointer; + color: white; + text-align: center; + user-select: none; /* Disable text selection */ +} + +@media (max-width: 768px) { + .check-btn { + padding: 4vw 6vw; /* Adjust padding for mobile */ + } +} + +/* Ensure no default checkbox styles */ +input[type="checkbox"] { + display: none; /* Hide the checkbox, it will be visually represented by the label */ +} + +#autonHeader, #endgameHeader, #teleopHeader1, #teleopHeader2{ + color: black; + border-color: black; + border-width: 4px; +} + +#postmatchHeader{ + border-width: 4px; + border-color: white; +} + +#prematchHeader1, #prematchHeader2{ + color: white; + border-color: white; + border-width: 4px; +} + +#qrHeader1, #qrHeader2 { + color: black; +} + +.field-image { + margin: 2vw; +} + +.field-image-src { + width: 225px; + max-width: 500px; + height: auto; + background-position: center; + border: 1px solid; +} + +.main-panel{ + display: none; + height: 100%; + min-height: 100%; + width: 100vw; + position: absolute; + left: 0; + top: 0; + color: white; + background-color: black; + font-family : Roboto, Oxygen, Ubuntu, Cantarell, 'Open Sans', 'Helvetica Neue', sans-serif !important; + text-align: justify; +} + +#prematch{ + display: table; +} + +#auton{ +} + +#teleop{ +} + +#endgame{ +} + +#postmatch{ +} + +#qr-code{ + text-align: center; + color: black; +} + +h1{ + font-family: Roboto; + text-align: center; + border-style: groove; + border-color: white; + border-width: 2px; + font-size: 40px; + padding: 10px; + font-weight: 500; +} + +#page2, #page4 { + color: black; +} + +h2{ + font-family: Roboto; + text-align: center; + font-size: 30px; + font-weight: 400; + font-style: italic; +} + +.match-label{ + text-align: center; +} + +.half-button-l{ + width: 48%; + margin: 1vw; + height: 100%; + font: roboto; +} + +.half-button-r{ + flex-grow: 1; + height: 100%; + width: 48%; + margin: 1vw; + font: roboto; +} + +.half-button-container{ + display: flex; +} + +#nextButton1, #nextButton2, #nextButton9, #nextButton10, .clearForm, .submitForm, #displayButton, #copyButton { + font-family: Roboto; + font-weight: 500; + padding: 10px; + background-color: rgb(151, 199, 240); + text-decoration: none; + display: inline-block; +} + +#nextButton3, #nextButton4, #nextButton5, #nextButton6, #nextButton7, #nextButton8 { + font-family: Roboto; + font-weight: 500; + background-color: black; + padding: 10px; + color: white; +} + +.undoButton, .flipButton { + font-family: Roboto; + font-weight: 500; + background-color: black; + padding: 10px; + color: white; + margin-left: 20px; +} + +#prevButton7, #prevButton8, #prevButton9{ + font-family: Roboto; + font-weight: 500; + background-color: rgb(151, 199, 240); + padding: 10px; +} + +#prevButton1, #prevButton2, #prevButton3, #prevButton4, #prevButton5, #prevButton6{ + font-family: Roboto; + font-weight: 500; + background-color: black; + padding: 10px; + color: white; + +} + +#prematch_table{ + font: Roboto; + font-weight: 500; + text-align: center; +} + + +h1 .odd { + font-family: Roboto; + font-weight: 500; + text-align: center; + color: #C0362C; +} + +h1 .even { + font-family: Roboto; + font-weight: 500; + text-align: center; + color: #C0362C; +} + +table { + border: 1px solid black; + width: 100%; +} + +td { + padding: 10px 4px; +} + +input { + font-size: 16px; + font: roboto; + color: black; + background-color: white; +} + +.title { + width: "50%"; + text-align: right; +} + +.field { + width: "50%"; + text-align: left; +} + +#qr-table { + text-align: center; + color: black; + background-color: white; +} + +#data { + font-family:'Lucida Console', 'monospace'; + text-align: justify; +} + +/* ── Qualitative scouting additions ─────────────────────────────────────── */ + +.qual-status-msg { + font-style: italic; + font-size: 0.9em; + text-align: center; + padding: 4px 0 8px; + min-height: 1.4em; +} + +.qual-hint { + font-size: 0.85em; + font-style: italic; + color: #ccc; + margin: 0 0 10px; +} + +.qual-divider { + border: none; + border-top: 1px solid #666; + margin: 6px 0; +} + +.qual-team-header { + font-weight: bold; + font-size: 1.0em; + padding: 8px 4px 4px; +} + +.qual-red { color: #ff6666; } +.qual-blue { color: #6699ff; } + +.qual-label { + font-weight: bold; + font-size: 0.9em; +} + +.qual-radio { + font-size: 0.88em; + margin-right: 6px; + white-space: nowrap; +} + +.qual-radio input[type="radio"] { + display: inline; /* override the hidden rule for checkboxes */ + width: auto; +} + +.qual-textarea { + width: 98%; + font-size: 0.9em; + padding: 4px; + box-sizing: border-box; + background-color: white; + color: black; +} + +/* Tier row */ +.qual-tier-row { + display: grid; + grid-template-columns: 140px repeat(5, 1fr); + align-items: center; + gap: 4px; + margin-bottom: 6px; +} + +.qual-tier-team { + font-weight: bold; + font-size: 0.9em; + min-width: 130px; +} + +.qual-tier-pills { + display: contents; /* lets each pill sit directly in the grid */ +} + +.qual-tier-pill { + display: block; + text-align: center; + padding: 4px 9px; + border: 1px solid #888; + border-radius: 4px; + font-size: 0.8em; + cursor: pointer; + user-select: none; + color: white; +} + +.qual-tier-pill input[type="radio"] { + display: none; +} + +.qual-tier-pill:has(input:checked) { + background-color: rgb(151, 199, 240); + color: black; + border-color: white; +} + +/* Within-tier drag ranking */ +.qual-rank-group { + margin: 14px 0 6px; +} + +.qual-rank-group-label { + font-size: 0.82em; + font-style: italic; + color: #bbb; + margin-bottom: 4px; +} + +.qual-rank-list { + list-style: none; + padding: 0; + margin: 0; +} + +.qual-rank-item { + display: flex; + align-items: center; + gap: 8px; + border: 1px solid #888; + border-radius: 4px; + padding: 6px 10px; + margin-bottom: 5px; + cursor: grab; + font-size: 0.92em; + background-color: rgba(255,255,255,0.08); + touch-action: none; +} + +.qual-rank-item:active { cursor: grabbing; } + +.qual-rank-item.qual-dragging { opacity: 0.4; } + +.qual-rank-item.qual-drag-over { + border: 1px dashed #fff; + background-color: rgba(255,255,255,0.22); +} + +.qual-drag-handle { + opacity: 0.5; + font-size: 1.1em; +} + +.qual-rank-name { + font-size: 0.85em; + opacity: 0.75; +} \ No newline at end of file diff --git a/resources/js/googleSheets.js b/resources/js/googleSheets.js index 99cdb646c..74d1ba66a 100644 --- a/resources/js/googleSheets.js +++ b/resources/js/googleSheets.js @@ -2,16 +2,19 @@ function setUpGoogleSheets() { const scriptURL = 'https://script.google.com/macros/s/AKfycbxYpArzIdDBCy3ZZmjH2KZTErAfJWl0OsqWO_46VfBQaPsyqC0CuW3rL8fK_Qp80zE/exec' const form = document.querySelector('#scoutingForm') const btn = document.querySelector('#submit') - - + + if (!form || !btn) return; + form.addEventListener('submit', e => { e.preventDefault() - btn.disabled = false + btn.disabled = true btn.innerHTML = "Sending..." let fd = getData("tsv"); if (pitScouting) { - fd = "PIT\t" + fd; + fd = "PIT\t" + fd; + } else if (typeof qualCollectData === 'function') { + fd = "QUAL\t" + qualCollectData(); } fetch(scriptURL, { method: "POST", @@ -27,3 +30,5 @@ function setUpGoogleSheets() { btn.innerHTML = "Send to Google Sheets" }) } + +