8888 body {
8989 font-family : 'Raleway' , sans-serif;
9090 background : # 313438 ;
91- /* background-image:
92- repeating-linear-gradient(90deg, transparent, transparent 2px, rgba(255, 255, 255, 0.01) 2px, rgba(255, 255, 255, 0.01) 4px); */
9391 color : white;
9492 overflow-x : hidden;
9593 min-height : 100vh ;
339337 body .simple-mode [data-theme ] .footer {
340338 background : rgb (207 , 207 , 207 );
341339 border : 2px solid rgba (0 , 0 , 0 , 0.08 );
342- /* border: 2px solid rgba(0, 0, 0, 0.08); */
343340 }
344341
345342 @media (max-width : 768px ) {
463460 backdrop-filter : none;
464461 }
465462
466- @media (max-width : 768px ) {
467- body .kindle-mode .footer {
468- left : 18px ;
469- transform : none;
470- }
471- }
472-
473463 .container {
474464 display : grid;
475465 gap : 0 ;
578568 backdrop-filter : none;
579569 }
580570
581- @media (max-width : 768px ) {
582- body .simple-mode .footer {
583- left : 18px ;
584- transform : none;
585- }
586- }
587-
588571 @media (max-width : 768px ) {
589572 .header {
590573 flex-direction : column;
@@ -1537,6 +1520,54 @@ <h1>J-Train</h1>
15371520 </ div >
15381521
15391522 < script >
1523+ // ============================================================
1524+ // URL PARAMETER SUPPORT
1525+ // All settings can be preset via URL for TV/Fire Stick installs.
1526+ //
1527+ // PARAMETERS:
1528+ // count Number of station panels: 1, 2, 3, or 4
1529+ // stations Comma-separated station IDs (e.g. 1028,1107)
1530+ // stationNames Comma-separated station name fragments
1531+ // (e.g. "Flinders,Richmond" — partial match OK)
1532+ // theme Display mode: "simple", "kindle", or "default"
1533+ // color Color theme name (see list below)
1534+ // fullscreen "true" or "1" to start in fullscreen
1535+ //
1536+ // COLOR THEME NAMES:
1537+ // default, cream-teal, sage-purple, yellow-navy, lime-forest,
1538+ // slate-blue, peach-brown, gold-navy, mint-navy, yellow-black, sky-coral
1539+ //
1540+ // EXAMPLES:
1541+ // Single station, fullscreen, kindle mode, mint-navy theme:
1542+ // ?count=1&stations=1028&theme=kindle&fullscreen=true&color=mint-navy
1543+ //
1544+ // Two stations by name, simple mode:
1545+ // ?count=2&stationNames=Flinders+Street,Richmond&theme=simple
1546+ //
1547+ // Four stations by ID, yellow-black theme:
1548+ // ?count=4&stations=1028,1107,1071,1144&color=yellow-black
1549+ //
1550+ // Just override stations without touching other settings:
1551+ // ?stations=1028,1107
1552+ //
1553+ // NOTE: URL params take priority over localStorage saved settings.
1554+ // Changing settings in the UI will still update localStorage
1555+ // for next time (without URL params).
1556+ // ============================================================
1557+
1558+ // Parse URL params early so they're available throughout init
1559+ const _urlParams = ( function ( ) {
1560+ const p = new URLSearchParams ( window . location . search ) ;
1561+ return {
1562+ count : p . get ( 'count' ) ,
1563+ stations : p . get ( 'stations' ) ,
1564+ stationNames : p . get ( 'stationNames' ) ,
1565+ theme : p . get ( 'theme' ) ,
1566+ color : p . get ( 'color' ) ,
1567+ fullscreen : p . get ( 'fullscreen' )
1568+ } ;
1569+ } ) ( ) ;
1570+
15401571 let allStations = [ ] ;
15411572 let stationCount = 2 ;
15421573 let selectedStations = [ 1028 , 1107 ] ;
@@ -1678,6 +1709,7 @@ <h1>J-Train</h1>
16781709 }
16791710 } ) ;
16801711
1712+ // ---- Theme initialisation (localStorage first, URL params override below) ----
16811713 const themeToggle = document . getElementById ( 'theme-toggle' ) ;
16821714 const savedTheme = localStorage . getItem ( 'trainTheme' ) ;
16831715 const savedColorTheme = localStorage . getItem ( 'colorTheme' ) ;
@@ -1688,8 +1720,7 @@ <h1>J-Train</h1>
16881720 } else if ( savedTheme === 'kindle' ) {
16891721 document . body . classList . add ( 'kindle-mode' ) ;
16901722 themeToggle . textContent = 'Simple' ;
1691- }
1692- else {
1723+ } else {
16931724 document . body . classList . add ( 'simple-mode' ) ;
16941725 themeToggle . textContent = 'Kindle' ;
16951726 }
@@ -1698,6 +1729,56 @@ <h1>J-Train</h1>
16981729 document . body . setAttribute ( 'data-theme' , savedColorTheme ) ;
16991730 }
17001731
1732+ // ---- Apply URL theme params (override localStorage) ----
1733+ if ( _urlParams . theme ) {
1734+ const t = _urlParams . theme . toLowerCase ( ) ;
1735+ document . body . classList . remove ( 'simple-mode' , 'kindle-mode' ) ;
1736+ if ( t === 'simple' ) {
1737+ document . body . classList . add ( 'simple-mode' ) ;
1738+ themeToggle . textContent = 'Kindle' ;
1739+ } else if ( t === 'kindle' ) {
1740+ document . body . classList . add ( 'kindle-mode' ) ;
1741+ themeToggle . textContent = 'Simple' ;
1742+ }
1743+ // 'default' = no extra class (dark mode)
1744+ }
1745+
1746+ if ( _urlParams . color ) {
1747+ const c = _urlParams . color . toLowerCase ( ) ;
1748+ if ( c === 'default' ) {
1749+ document . body . removeAttribute ( 'data-theme' ) ;
1750+ } else {
1751+ document . body . setAttribute ( 'data-theme' , c ) ;
1752+ }
1753+ }
1754+
1755+ if ( _urlParams . fullscreen === 'true' || _urlParams . fullscreen === '1' ) {
1756+ document . body . classList . add ( 'fullscreen-mode' ) ;
1757+ fullscreenBtn . textContent = 'Exit' ;
1758+ }
1759+
1760+ // ---- Override station IDs from URL before list loads ----
1761+ if ( _urlParams . count ) {
1762+ const urlCount = Math . min ( 4 , Math . max ( 1 , parseInt ( _urlParams . count ) ) ) ;
1763+ if ( ! isNaN ( urlCount ) ) {
1764+ stationCount = urlCount ;
1765+ document . getElementById ( 'station-count' ) . value = urlCount ;
1766+ }
1767+ }
1768+
1769+ if ( _urlParams . stations ) {
1770+ const ids = _urlParams . stations . split ( ',' )
1771+ . map ( s => parseInt ( s . trim ( ) ) )
1772+ . filter ( n => ! isNaN ( n ) ) ;
1773+ if ( ids . length > 0 ) {
1774+ // Pad or trim to match stationCount
1775+ selectedStations = Array . from ( { length : stationCount } , ( _ , i ) =>
1776+ ids [ i ] !== undefined ? ids [ i ] : ids [ ids . length - 1 ]
1777+ ) ;
1778+ }
1779+ }
1780+
1781+ // ---- Theme toggle button handler ----
17011782 themeToggle . addEventListener ( 'click' , ( ) => {
17021783 if ( document . body . classList . contains ( 'simple-mode' ) ) {
17031784 document . body . classList . remove ( 'simple-mode' ) ;
@@ -1708,16 +1789,18 @@ <h1>J-Train</h1>
17081789 startUpdates ( ) ;
17091790 } else {
17101791 document . body . classList . add ( 'simple-mode' ) ;
1792+ document . body . classList . remove ( 'kindle-mode' ) ;
17111793 themeToggle . textContent = 'Kindle' ;
17121794 localStorage . setItem ( 'trainTheme' , 'simple' ) ;
1713- // document.querySelector('.station-selector').style.display = 'visible';
1714- // startUpdates();
17151795 }
17161796 } ) ;
17171797
1798+ // ---- Color theme boxes ----
17181799 document . querySelectorAll ( '.theme-color-box' ) . forEach ( box => {
17191800 const theme = box . dataset . theme ;
1720- if ( theme === savedColorTheme || ( ! savedColorTheme && theme === 'default' ) ) {
1801+ // Determine active state: URL param takes priority, then localStorage
1802+ const activeTheme = _urlParams . color || savedColorTheme || 'default' ;
1803+ if ( theme === activeTheme || ( ! activeTheme && theme === 'default' ) ) {
17211804 box . classList . add ( 'active' ) ;
17221805 }
17231806
@@ -1849,6 +1932,26 @@ <h2 class="station-name" id="station-name-${index}">Select Station</h2>
18491932 a . stop_name . localeCompare ( b . stop_name )
18501933 ) ;
18511934
1935+ // ---- Resolve stationNames URL param now that list is loaded ----
1936+ if ( _urlParams . stationNames ) {
1937+ const names = _urlParams . stationNames . split ( ',' ) . map ( s => s . trim ( ) . toLowerCase ( ) ) ;
1938+ const resolvedIds = names . map ( name => {
1939+ const match = allStations . find ( s => {
1940+ const clean = s . stop_name . toLowerCase ( )
1941+ . replace ( ' railway station' , '' )
1942+ . replace ( ' station' , '' ) ;
1943+ return clean === name || clean . includes ( name ) || s . stop_name . toLowerCase ( ) . includes ( name ) ;
1944+ } ) ;
1945+ return match ? match . stop_id : null ;
1946+ } ) . filter ( id => id !== null ) ;
1947+
1948+ if ( resolvedIds . length > 0 ) {
1949+ selectedStations = Array . from ( { length : stationCount } , ( _ , i ) =>
1950+ resolvedIds [ i ] !== undefined ? resolvedIds [ i ] : resolvedIds [ resolvedIds . length - 1 ]
1951+ ) ;
1952+ }
1953+ }
1954+
18521955 updateStationCount ( stationCount ) ;
18531956 }
18541957 } catch ( error ) {
@@ -1974,8 +2077,6 @@ <h2 class="station-name" id="station-name-${index}">Select Station</h2>
19742077 }
19752078
19762079 async function updateAllTrains ( ) {
1977- const isKindle = document . body . classList . contains ( 'kindle-mode' ) ;
1978-
19792080 const promises = selectedStations . map ( stationId => fetchTrains ( stationId ) ) ;
19802081 const results = await Promise . all ( promises ) ;
19812082
0 commit comments