Pivotonian

Sports Scores

Sep 23rd, 2025
71
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
text 24.79 KB | None | 0 0
  1. type: custom:button-card
  2. entity: '[[[ return variables.var_entity ]]]'
  3. tap_action:
  4. action: url
  5. url_path: |
  6. [[[
  7. return entity.attributes.event_url;
  8. ]]]
  9. show_icon: false
  10. show_name: false
  11. show_state: false
  12. styles:
  13. grid:
  14. - grid-template-areas: |
  15. "summary summary summary"
  16. "venue venue venue"
  17. "home time away"
  18. "status status status"
  19. "card card card"
  20. - grid-template-columns: 1fr min-content 1fr
  21. - grid-template-rows: min-content min-content 1fr min-content
  22. - align-items: center
  23. - justify-content: space-between
  24. card:
  25. - box-sizing: border-box
  26. - width: 302.5px
  27. - height: 375px
  28. - background-color: transparent
  29. - background-image: |
  30. [[[
  31. let teamColor = entity.attributes.team_colors[0];
  32. let opponentColor = entity.attributes.opponent_colors[0];
  33. return `radial-gradient(circle at 1% center, ${teamColor} 0%, ${teamColor} 10%, rgba(0,0,0,0.7) 70%),
  34. radial-gradient(circle at 99% center, ${opponentColor} 50%, ${opponentColor} 10%, rgba(0,0,0,0.7) 100%)`;
  35. ]]]
  36. - background-size: cover
  37. - background-position: center
  38. - background-repeat: no-repeat
  39. - border: solid 2px transparent
  40. - border-radius: 35px
  41. - padding: 15px 0px 0px 0px
  42. - margin: 0px 0px 0px 0px
  43. custom_fields:
  44. summary:
  45. card:
  46. type: custom:layout-card
  47. layout_type: custom:grid-layout
  48. layout:
  49. grid-template-areas: '"summary"'
  50. grid-template-columns: 1fr
  51. grid-template-rows: auto
  52. cards:
  53. - view_layout:
  54. grid-area: summary
  55. type: custom:button-card
  56. tap_action:
  57. action: url
  58. url_path: |
  59. [[[
  60. return entity.attributes.event_url;
  61. ]]]
  62. show_label: true
  63. show_name: true
  64. show_icon: false
  65. show_state: false
  66. name: |
  67. [[[
  68. return `${entity.attributes.team_name} v ${entity.attributes.opponent_name}`;
  69. ]]]
  70. label: |
  71. [[[
  72. let utcDate = new Date(entity.attributes.date);
  73.  
  74. // Convert UTC date to Sydney time (AEST/AEDT)
  75. let aestDate = new Intl.DateTimeFormat("en-AU", {
  76. weekday: "long",
  77. day: "numeric",
  78. month: "long",
  79. year: "numeric",
  80. hour: "numeric",
  81. minute: "numeric",
  82. hour12: true,
  83. timeZone: "Australia/Sydney"
  84. }).format(utcDate);
  85.  
  86. return aestDate.replace("AM", "AM AEST").replace("PM", "PM AEST");
  87. ]]]
  88. styles:
  89. card:
  90. - background: transparent
  91. padding: 0 0 0 0px
  92. margin: 0px
  93. border-radius: 0px
  94. - height: 40px
  95. name:
  96. - font-size: .9em
  97. font-weight: 700
  98. label:
  99. - font-size: .9em
  100. padding-top: 3px
  101. color: rgba(255,255,255,0.4)
  102. venue:
  103. card:
  104. type: custom:button-card
  105. show_label: true
  106. show_name: false
  107. show_icon: false
  108. show_state: false
  109. label: |
  110. [[[
  111. return entity.attributes.venue;
  112. ]]]
  113. styles:
  114. card:
  115. - background: transparent
  116. - padding: 0px
  117. - text-align: center
  118. - height: 30px
  119. label:
  120. - font-size: .9em
  121. - font-weight: 400
  122. - color: rgba(255,255,255,0.4)
  123. home_win_gap:
  124. card:
  125. type: custom:button-card
  126. show_label: true
  127. show_name: false
  128. show_icon: false
  129. show_state: false
  130. label: |
  131. [[[
  132. let teamScore = entity.attributes.team_score || 0;
  133. let oppScore = entity.attributes.opponent_score || 0;
  134. let diff = teamScore - oppScore;
  135.  
  136. if (entity.state === "PRE") {
  137. return `${entity.attributes.team_record}`; // Just return the number
  138. }
  139.  
  140. return (diff > 0) ? `+${diff}` : "";
  141. ]]]
  142. styles:
  143. card:
  144. - background: transparent
  145. - text-align: end
  146. - align-content: end
  147. - justify-content: end
  148. - padding: 0px 13px 10px 10px
  149. - margin: 0px 0px 0px 0px
  150. label:
  151. - font-size: |
  152. [[[
  153. return (entity.state === "PRE")
  154. ? ".7em"
  155. : ".9em";
  156. ]]]
  157. - font-weight: |
  158. [[[
  159. return (entity.state === "PRE")
  160. ? "400"
  161. : "600";
  162. ]]]
  163. - color: |
  164. [[[
  165. return (entity.state === "PRE")
  166. ? "grey"
  167. : "var(--label-badge-blue)";
  168. ]]]
  169. - text-align: end
  170. - align-content: end
  171. - justify-content: end
  172. away_win_gap:
  173. card:
  174. type: custom:button-card
  175. show_label: true
  176. show_name: false
  177. show_icon: false
  178. show_state: false
  179. label: |
  180. [[[
  181. let teamScore = entity.attributes.team_score || 0;
  182. let oppScore = entity.attributes.opponent_score || 0;
  183. let diff = oppScore - teamScore;
  184.  
  185. if (entity.state === "PRE") {
  186. return `${entity.attributes.opponent_record}`; // Just return the number
  187. }
  188.  
  189. return (["IN", "POST"].includes(entity.state) && diff > 0)
  190. ? `+${diff}`
  191. : "";
  192. ]]]
  193. styles:
  194. card:
  195. - background: transparent
  196. - text-align: start
  197. - padding: 0px 13px 10px 10px
  198. label:
  199. - font-size: |
  200. [[[
  201. return (entity.state === "PRE")
  202. ? ".7em"
  203. : ".9em";
  204. ]]]
  205. - font-weight: |
  206. [[[
  207. return (entity.state === "PRE")
  208. ? "400"
  209. : "600";
  210. ]]]
  211. - color: |
  212. [[[
  213. return (entity.state === "PRE")
  214. ? "grey"
  215. : "var(--label-badge-blue)";
  216. ]]]
  217. - text-align: start
  218. home:
  219. card:
  220. type: custom:button-card
  221. show_label: true
  222. show_name: true
  223. show_icon: false
  224. show_state: false
  225. tap_action:
  226. action: url
  227. url_path: |
  228. [[[
  229. return entity.attributes.event_url;
  230. ]]]
  231. name: |
  232. [[[
  233. let team_abbr = entity.attributes.team_abbr || "N/A";
  234. let logo_url = `/local/images/afl/${team_abbr.toLowerCase()}.svg`;
  235.  
  236. // Manual override for missing images
  237. let known_logos = ["adel", "bl", "carl", "coll", "ess", "fre", "geel", "gcfc", "gws", "haw", "melb", "nmfc", "port", "rich", "stk", "syd", "wce", "wb"];
  238. if (!known_logos.includes(team_abbr.toLowerCase())) {
  239. logo_url = `/local/images/afl/gcfc.svg`; // Fallback image
  240. }
  241.  
  242. return `<img src="${logo_url}" style="width:65px;height:65px;">`;
  243. ]]]
  244. label: |
  245. [[[
  246. return entity.state === "PRE" ? entity.attributes.team_abbr : entity.attributes.team_score;
  247. ]]]
  248. styles:
  249. card:
  250. - background: transparent
  251. - padding: 0px 0px 0px 0px
  252. - margin: '-30px 0px 10px 0px'
  253. - width: 110px
  254. - height: 170px
  255. - border-radius: 0px
  256. - filter: |
  257. [[[
  258. let homeScore = parseInt(entity.attributes.team_score, 10) || 0;
  259. let awayScore = parseInt(entity.attributes.opponent_score, 10) || 0;
  260. let isPostGame = entity.state === "POST";
  261.  
  262. return isPostGame && homeScore < awayScore ? "opacity(1)" : "none";
  263. ]]]
  264. - align-content: start
  265. align-self: start
  266. justify-content: start
  267. justify-self: start
  268. name:
  269. - align-content: end
  270. align-self: end
  271. justify-content: center
  272. justify-self: center
  273. margin: 10px 0px -30px 0px
  274. filter: >-
  275. drop-shadow(1px 0 0 rgba(255,255,255,0.8)) drop-shadow(-1px 0
  276. 0 rgba(255,255,255,0.8)) drop-shadow(0 1px 0
  277. rgba(255,255,255,0.8)) drop-shadow(0 -1px 0
  278. rgba(255,255,255,0.8))
  279. label:
  280. - font-size: |
  281. [[[
  282. return entity.state === "PRE" ? "1em" : "2em";
  283. ]]]
  284. - font-weight: 700
  285. - padding-top: 50px
  286. - color: |
  287. [[[
  288. if (entity.state === "PRE") {
  289. return "white";
  290. }
  291.  
  292. let homeScore = parseInt(entity.attributes.team_score, 10);
  293. let awayScore = parseInt(entity.attributes.opponent_score, 10);
  294.  
  295. if (homeScore === awayScore) {
  296. return "white"; // Both scores white when tied
  297. }
  298.  
  299. return (homeScore < awayScore)
  300. ? "rgba(255, 255, 255, 0.5)" // Dimmed if HOME wins
  301. : "white"; // Fully visible if HOME loses
  302. ]]]
  303. - align-content: end
  304. align-self: end
  305. justify-content: center
  306. justify-self: center
  307. font-family: Chromatic Gothic Semibold, sans-serif
  308. time:
  309. card:
  310. type: custom:button-card
  311. show_label: true
  312. show_name: false
  313. show_icon: false
  314. show_state: false
  315. tap_action:
  316. action: url
  317. url_path: |
  318. [[[
  319. return entity.attributes.event_url;
  320. ]]]
  321. label: |
  322. [[[
  323. if (entity.state && entity.state.toUpperCase() === "PRE") {
  324. return "VS"; // Show 'VS' instead of the time
  325. }
  326.  
  327. let clock = entity.attributes.clock || "";
  328.  
  329. // Handle custom quarter names
  330. let clockAdjustments = {
  331. "End of 3rd": "3QT",
  332. "Halftime": "HT",
  333. "End of 2nd": "QT",
  334. "Fulltime": "FT"
  335. };
  336.  
  337. if (clockAdjustments[clock]) {
  338. return clockAdjustments[clock];
  339. }
  340.  
  341. // Adjust format if clock includes a hyphen separator
  342. if (clock.includes(" - ")) {
  343. let [quarter, timeLeft] = clock.split(" - ");
  344. return `${timeLeft}<br>${quarter}`;
  345. }
  346.  
  347. return clock;
  348. ]]]
  349. styles:
  350. card:
  351. - background: |
  352. [[[
  353. let clock = entity.attributes.clock || "";
  354.  
  355. // Define states that should have a black background
  356. let blackBackgroundStates = ["QT", "HT", "3QT", "FT"];
  357.  
  358. // Handle custom quarter names
  359. let clockAdjustments = {
  360. "End of 3rd": "3QT",
  361. "Halftime": "HT",
  362. "End of 2nd": "QT",
  363. "Fulltime": "FT"
  364. };
  365.  
  366. if (clockAdjustments[clock]) {
  367. clock = clockAdjustments[clock];
  368. }
  369.  
  370. if (blackBackgroundStates.includes(clock)) {
  371. return "rgba(75,75,80,0.2)";
  372. } else if (entity.state === "IN") {
  373. return "var(--label-badge-green)";
  374. } else if (entity.state === "POST") {
  375. return "rgba(75,75,80,0.2)";
  376. } else if (entity.state === "PRE") {
  377. return "transparent";
  378. }
  379.  
  380. return "transparent";
  381. ]]]
  382. - padding: |
  383. [[[
  384. if (entity.state === "PRE") {
  385. return "0px 0px 0px 0px"; // No background color before the game starts
  386. } else if (entity.state === "IN") {
  387. return "8px 0px 8px 0px"; // Green when game is in progress
  388. } else if (entity.state === "POST") {
  389. return "8px 0px 8px 0px"; // Red after the game ends
  390. }
  391. return "transparent"; // Default to no background
  392. ]]]
  393. - margin: |
  394. [[[
  395. if (entity.state === "PRE") {
  396. return "5px 0px 0px 0px"; // No background color before the game starts
  397. } else if (entity.state === "IN") {
  398. return "5px 10px 0px 10px"; // Green when game is in progress
  399. } else if (entity.state === "POST") {
  400. return "5px 10px 0px 10px"; // Red after the game ends
  401. }
  402. return "transparent"; // Default to no background
  403. ]]]
  404. - width: |
  405. [[[
  406. if (entity.state === "PRE") {
  407. return "60px"; // No background color before the game starts
  408. } else if (entity.state === "IN") {
  409. return "60px"; // Green when game is in progress
  410. } else if (entity.state === "POST") {
  411. return "100px"; // Red after the game ends
  412. }
  413. return "transparent"; // Default to no background
  414. ]]]
  415. - border-radius: 5px
  416. - justify-content: center
  417. - align-content: end
  418. - align-self: end
  419. - justify-self: center
  420. - justify-content: center
  421. label:
  422. - font-size: |
  423. [[[
  424. if (entity.state === "PRE") {
  425. return ".8em"; // No background color before the game starts
  426. } else if (entity.state === "IN") {
  427. return "0.9em"; // Green when game is in progress
  428. } else if (entity.state === "POST") {
  429. return "0.8em"; // Red after the game ends
  430. }
  431. return "transparent"; // Default to no background
  432. ]]]
  433. - font-weight: 600
  434. away:
  435. card:
  436. type: custom:button-card
  437. show_label: true
  438. show_name: true
  439. show_icon: false
  440. show_state: false
  441. tap_action:
  442. action: url
  443. url_path: |
  444. [[[
  445. return entity.attributes.event_url;
  446. ]]]
  447. name: |
  448. [[[
  449. let team_abbr = entity.attributes.opponent_abbr || "N/A";
  450. let logo_url = `/local/images/afl/${team_abbr.toLowerCase()}.svg`;
  451.  
  452. // Manual override for missing images
  453. let known_logos = ["adel", "bl", "carl", "coll", "ess", "fre", "geel", "gcfc", "gws", "haw", "melb", "nmfc", "port", "rich", "stk", "syd", "wce", "wb"];
  454. if (!known_logos.includes(team_abbr.toLowerCase())) {
  455. logo_url = `/local/images/afl/gcfc.svg`; // Fallback image
  456. }
  457.  
  458. return `<img src="${logo_url}" style="width:65px;height:65px;">`;
  459. ]]]
  460. label: |
  461. [[[
  462. return entity.state === "PRE" ? entity.attributes.opponent_abbr : entity.attributes.opponent_score;
  463. ]]]
  464. styles:
  465. label:
  466. - font-size: |
  467. [[[
  468. return entity.state === "PRE" ? "1em" : "2em";
  469. ]]]
  470. - font-weight: 700
  471. - padding-top: 50px
  472. - color: |
  473. [[[
  474. if (entity.state === "PRE") {
  475. return "white";
  476. }
  477.  
  478. let homeScore = parseInt(entity.attributes.team_score, 10);
  479. let awayScore = parseInt(entity.attributes.opponent_score, 10);
  480.  
  481. if (homeScore === awayScore) {
  482. return "white"; // Both scores white when tied
  483. }
  484.  
  485. return (homeScore > awayScore)
  486. ? "rgba(255, 255, 255, 0.5)" // Dimmed if AWAY wins
  487. : "white"; // Fully visible if AWAY loses
  488. ]]]
  489. - align-content: end
  490. align-self: end
  491. justify-content: center
  492. justify-self: center
  493. font-family: Chromatic Gothic Semibold, sans-serif
  494. name:
  495. - align-content: end
  496. align-self: end
  497. justify-content: center
  498. justify-self: center
  499. margin: 0px 0px -30px 0px
  500. padding: 0px
  501. filter: >-
  502. drop-shadow(1px 0 0 rgba(255,255,255,0.8)) drop-shadow(-1px 0
  503. 0 rgba(255,255,255,0.8)) drop-shadow(0 1px 0
  504. rgba(255,255,255,0.8)) drop-shadow(0 -1px 0
  505. rgba(255,255,255,0.8))
  506. card:
  507. - background: transparent
  508. - padding: 0px 0px 0px 0px
  509. - width: 110px
  510. - height: 170px
  511. - margin: '-30px 0px 10px 0px'
  512. - border-radius: 0px
  513. - opacity: |
  514. [[[
  515. let sensor = states['sensor.afl_ladder'];
  516. let index = parseInt(variables.var_index, 10);
  517.  
  518. if (sensor?.attributes?.entries?.length > index) {
  519. let entry = sensor.attributes.entries[index].summary;
  520. let status = entry.match(/Status:\s*<\/strong>(.*?)<\/p>/)?.[1] || "N/A";
  521. return status === "POST" ? "0.5" : "1"; // Reduce opacity if game is finished
  522. }
  523. return "1"; // Default full opacity if data is unavailable
  524. ]]]
  525. - filter: |
  526. [[[
  527. let homeScore = parseInt(entity.attributes.team_score, 10) || 0;
  528. let awayScore = parseInt(entity.attributes.opponent_score, 10) || 0;
  529. let isPostGame = entity.state === "POST";
  530.  
  531. return isPostGame && awayScore < homeScore ? "opacity(1)" : "none";
  532. ]]]
  533. status:
  534. card:
  535. type: custom:layout-card
  536. layout_type: custom:grid-layout
  537. layout:
  538. grid-template-areas: '"match_status"'
  539. grid-template-columns: 1fr
  540. grid-template-rows: auto
  541. cards:
  542. - view_layout:
  543. grid-area: match_status
  544. type: custom:button-card
  545. tap_action:
  546. action: url
  547. url_path: |
  548. [[[
  549. return entity.attributes.event_url;
  550. ]]]
  551. show_label: true
  552. show_name: false
  553. show_icon: false
  554. show_state: false
  555. label: |
  556. [[[
  557. let state = entity.state;
  558. let diff = entity.attributes.team_score - entity.attributes.opponent_score;
  559.  
  560. if (state === 'PRE') {
  561. return `Bounce ${entity.attributes.kickoff_in}`;
  562. }
  563. else if (state === 'IN') {
  564. if (diff > 0) {
  565. return `${entity.attributes.team_name} lead by ${diff} ${diff === 1 ? "point" : "points"}`;
  566. } else if (diff < 0) {
  567. return `${entity.attributes.opponent_name} lead by ${Math.abs(diff)} ${Math.abs(diff) === 1 ? "point" : "points"}`;
  568. } else {
  569. return `Match tied`;
  570. }
  571. }
  572. else if (state === 'POST') {
  573. if (diff > 0) {
  574. return `${entity.attributes.team_name} won by ${diff} ${diff === 1 ? "point" : "points"}`;
  575. } else if (diff < 0) {
  576. return `${entity.attributes.opponent_name} won by ${Math.abs(diff)} ${Math.abs(diff) === 1 ? "point" : "points"}`;
  577. } else {
  578. return `Match tied`;
  579. }
  580. }
  581. else {
  582. return `Match tied`;
  583. }
  584. ]]]
  585. styles:
  586. card:
  587. - background: transparent
  588. padding: 0px
  589. margin: 0px
  590. height: 40px
  591. align-content: center
  592. justify-content: center
  593. label:
  594. - font-size: .9em
  595. font-weight: 700
  596. color: rgba(255,255,255,1)
  597. padding: 10px 0px 20px 0px
  598. margin: 0px
  599. card:
  600. card:
  601. type: custom:button-card
  602. tap_action:
  603. action: perform-action
  604. perform_action: script.kayo
  605. show_label: true
  606. show_name: false
  607. show_icon: false
  608. show_state: false
  609. label: Watch on Kayo
  610. styles:
  611. card:
  612. - background: rgba(0,0,0,0.4)
  613. - border-radius: 10px
  614. - padding: 0px 30px 0px 30px
  615. - margin: '-10px 0px 0px 30px'
  616. - text-align: center
  617. - height: 40px
  618. - width: 240px
  619. - align-content: center
  620. - align-self: center
  621. - justify-content: center
  622. - justify-self: center
  623. label:
  624. - font-size: .9em
  625. - font-weight: 400
  626. - color: rgba(255,255,255,0.6)
  627. card_mod:
  628. style: |
  629. :host {
  630. display: block;
  631. position: relative; margin: 0px 6px 0px 0px;
  632. }
  633.  
  634. :host::before {
  635.  
  636. content: "";
  637. position: absolute;
  638. inset: 0;
  639. border-radius: 30px;
  640. backdrop-filter: blur(50px);
  641. -webkit-backdrop-filter: blur(50px);
  642. z-index: -1;
  643. padding: .1rem;
  644. background: linear-gradient(60deg,
  645. rgba(255,255,255,0.0) 0%,
  646. rgba(255,255,255,0.2) 49%,
  647. rgba(255,255,255,0.2) 51%,
  648. rgba(255,255,255,0.0) 100%);
  649. -webkit-mask:
  650. linear-gradient(#fff 0 0) content-box,
  651. linear-gradient(#fff 0 0);
  652. -webkit-mask-composite: xor;
  653. mask-composite: exclude;
  654. z-index: 0; filter: saturate(140%);
  655. }
  656.  
  657. :host::after {
  658. content: "";
  659. background: linear-gradient(180deg, rgba(255,255,255, 0.1) 20%, rgba(255,255,255, 0.0) 100%);
  660. position: absolute;
  661. inset: 0;
  662. border-radius: 30px;
  663. box-shadow: inset -8px 10px 15px rgba(0, 0, 0, 0.1);
  664. z-index: -1;
  665.  
  666. -webkit-backdrop-filter:blur(30px) saturate(110%) brightness(90%);
  667. filter: drop-shadow(3px 3px 10px rgba(0, 0, 0, 0.2)); }
Advertisement
Add Comment
Please, Sign In to add comment