Add tunnel component and map connector component

This commit is contained in:
2026-02-05 22:02:31 +00:00
parent 4220cdfa5e
commit 4280ffe763
8 changed files with 404 additions and 93 deletions

23
Dockerfile Normal file
View File

@@ -0,0 +1,23 @@
FROM node:20-slim AS builder
WORKDIR /app
COPY package*.json ./
RUN npm ci
COPY . .
RUN node ./scripts/parse-maps.js
RUN npm run build
RUN npm prune --production
FROM node:20-slim
WORKDIR /app
COPY --from=builder /app/build ./build
COPY --from=builder /app/node_modules ./node_modules
COPY --from=builder /app/package.json ./package.json
USER node
ENV NODE_ENV=production
EXPOSE 3000
CMD ["node", "build"]

View File

@@ -4,7 +4,7 @@
export let feature: {
direction: 'up' | 'down';
diverges: 'left' | 'right';
diverges: 'left' | 'right' | 'both';
elecBranch?: string;
};
export let activeElec: any;
@@ -13,18 +13,25 @@
$: isUp = feature.direction === 'up';
$: visualUp = reversed ? !isUp : isUp;
$: isRight = feature.diverges === 'right';
const getPath = (side: 'left' | 'right') => {
const yStart = visualUp ? 64 : 0;
const yEnd = visualUp ? 8 : 56;
const xEnd = side === 'right' ? 56 : 8;
return `M 32 ${yStart} Q 32 32 ${xEnd} ${yEnd}`;
};
$: yStart = visualUp ? 64 : 0;
$: yEnd = visualUp ? 8 : 56;
$: xEnd = isRight ? 56 : 8;
$: paths = (() => {
if (feature.diverges === 'both') return [getPath('left'), getPath('right')];
return [getPath(feature.diverges)];
})();
$: branchColour = getElecColour(feature.elecBranch || activeElec);
$: branchPath = `M 32 ${yStart} Q 32 32 ${xEnd} ${yEnd}`;
</script>
<svg viewBox="0 0 64 64" width="64" height="64" class="junction">
<path d={branchPath} fill="none" stroke={branchColour} stroke-width="5" strone-linecap="round" />
{#each paths as d}
<path {d} fill="none" stroke={branchColour} stroke-width="5" stroke-linecap="round" />
{/each}
<BaseTrack {activeElec} height={64} />
</svg>

View File

@@ -0,0 +1,93 @@
<script lang="ts">
export let feature: {
routeName: string;
routeId: string;
};
</script>
<div class="link-wrapper">
<a href="/map/{feature.routeId}" class="wide-button">
<div class="accent-bar"></div>
<div class="content">
<span class="sub-text">Continue to next map</span>
<span class="main-text">{feature.routeName}</span>
</div>
<div class="icon">
<svg viewBox="0 0 24 24" width="20" height="20">
<path d="M5 12h14M12 5l7 7-7 7" fill="none" stroke="currentColor" stroke-width="2.5" stroke-linecap="round" stroke-linejoin="round"/>
</svg>
</div>
</a>
</div>
<style>
.link-wrapper {
position: relative;
z-index: 100;
padding: 12px;
width: 100%;
box-sizing: border-box;
}
.wide-button {
display: flex;
align-items: center;
background: #ffffff;
border: 2px solid #e2e8f0;
border-radius: 12px;
text-decoration: none;
overflow: hidden;
transition: all 0.2s cubic-bezier(0.4, 0, 0.2, 1);
box-shadow: 0 4px 6px -1px rgba(0, 0, 0, 0.05);
}
.accent-bar {
width: 6px;
align-self: stretch;
background: #475569;
}
.content {
flex: 1;
padding: 12px 16px;
display: flex;
flex-direction: column;
gap: 2px;
}
.sub-text {
font-size: 10px;
font-weight: 700;
text-transform: uppercase;
letter-spacing: 0.05em;
color: #94a3b8;
}
.main-text {
font-size: 16px;
font-weight: 800;
color: #1e293b;
}
.icon {
padding-right: 20px;
color: #cbd5e1;
transition: transform 0.2s ease;
}
.wide-button:hover {
border-color: #94a3b8;
background: #f8fafc;
}
.wide-button:hover .icon {
color: #475569;
transform: translateX(4px);
}
.wide-button:active {
transform: scale(0.98);
background: #f1f5f9;
}
</style>

View File

@@ -0,0 +1,56 @@
<script lang="ts">
import BaseTrack from "./BaseTrack.svelte";
export let feature: {
tunnelType: "start" | "whole" | "end";
length: string;
};
export let activeElec: any;
export let reversed: boolean = false;
const portalColour = "#475569"; // Slate grey
$: effectiveType = (() => {
if (!reversed || feature.tunnelType === 'whole') return feature.tunnelType;
return feature.tunnelType === 'start' ? 'end' : 'start';
})();
</script>
<svg viewBox="0 0 64 64" width="64" height="64" class="tunnel">
<BaseTrack {activeElec} height={64} />
<g fill="none" stroke={portalColour} stroke-width="3" stroke-linecap="round">
{#if effectiveType === 'whole'}
<path d="M 16 12 Q 32 24 48 12" />
<path d="M 16 52 Q 32 40 48 52" />
{:else if effectiveType === 'start'}
<path d="M 16 12 Q 32 24 48 12" />
{:else if effectiveType === 'end'}
<path d="M 16 52 Q 32 40 48 52" />
{/if}
</g>
{#if feature.tunnelType === 'whole' && feature.length}
<rect x="12" y="26" width="40" height="12" fill="white" />
<text
x="32"
y="35"
text-anchor="middle"
font-size="8.5"
font-weight="bold"
fill={portalColour}
class="t-text"
>
{feature.length}
</text>
{/if}
</svg>
<style>
svg { display: block; overflow: visible; }
.t-text { font-family: ui-monospace, monospace; }
</style>

View File

@@ -8,6 +8,7 @@ import Loop from '$lib/components/mapIcons/Loop.svelte';
import SignallerChange from '$lib/components/mapIcons/SignallerChange.svelte';
import ElectrificationChange from '$lib/components/mapIcons/ElectrificationChange.svelte';
import SiteOf from '$lib/components/mapIcons/SiteOf.svelte';
import Tunnel from '$lib/components/mapIcons/Tunnel.svelte';
export const components = {
station: Station,
@@ -21,5 +22,6 @@ export const components = {
loops: Loop,
signallerChange: SignallerChange,
electrificationChange: ElectrificationChange,
default: BaseTrack
default: BaseTrack,
tunnel: Tunnel,
};

View File

@@ -0,0 +1,8 @@
import { json } from '@sveltejs/kit';
import type { RequestHandler } from './$types';
export const GET: RequestHandler = () => {
return json({ status: 'ok', uptime: process.uptime() }, {
status: 200
});
};

View File

@@ -1,5 +1,6 @@
<script lang="ts">
import RouteRow from '$lib/components/RouteRow.svelte';
import RouteEndLink from '$lib/components/mapIcons/RouteEndLink.svelte';
import { slide } from 'svelte/transition';
// data.route contains: routeName, routeId, elecStart, elecEnd, routeDetail[]
@@ -15,7 +16,8 @@
signallerChange: true,
electrificationChange: true,
siteof: true,
junction: true
junction: true,
tunnel: true,
};
let showFilters = false;
@@ -106,12 +108,15 @@
<main class="map-spine">
<div class="container">
{#each filteredFeatures as f, i (`${f.type}-${f.miles}-${f.chains}-${i}`)}
{#if (f.type === 'continues')}
<RouteEndLink feature={f} />
{:else}
<RouteRow feature={f} activeElec={f.activeElec} {reversed} />
{/if}
{/each}
</div>
</main>
</div>
<style>
.map-layout {
display: flex;

View File

@@ -1,7 +1,6 @@
routeName: Paddington - Reading
routeName: Paddington - Reading West Jn
routeId: 0001
signallerStart: TVSC Paddington WS
# signallerEnd: TVSC Temple Meads WS
signallerEnd: TVSC Reading WS
elecStart:
elec: 25kvac
@@ -17,17 +16,14 @@ routeDetail:
chains: 5
- type: bridge
name: Westbourne
description: Westbourne Avenue
name: Westbourne Bridge
position: over
category: aroad
roadName: A412
category: minorRoad
miles: 0
chains: 33
- type: bridge
name: Ranelagh Bridge
description: Ranelegh Lane?
position: over
category: minorRoad
miles: 0
@@ -46,8 +42,9 @@ routeDetail:
- type: bridge
name: Lord's Hill Bridge
roadName: B411
position: over
category: road
category: minorRoad
miles: 0
chains: 52
@@ -65,6 +62,8 @@ routeDetail:
- type: crossovers
description: Royal Oak Carriage Loop A&B diverge
miles: 0
chains: 75
- type: bridge
name: Great Western Road
@@ -77,8 +76,8 @@ routeDetail:
- type: bridge
name: Westway
position: over
category: motorway
roadName: A40(M)
category: aroad
roadName: A40
miles: 1
chains: 18
@@ -96,7 +95,7 @@ routeDetail:
chains: 33
- type: bridge
name: Godbourne Road
name: Golbourne Road
position: over
category: minorRoad
miles: 1
@@ -113,7 +112,7 @@ routeDetail:
name: Ladbroke Grove
diverges: both
direction: down
destination: Crossrail Depot & North Pole Depot
description: to Crossrail & North Pole Depots
miles: 1
chains: 73
@@ -121,7 +120,7 @@ routeDetail:
name: Kensal Green South Junction
diverges: right
direction: down
destination: Crossrail Depot & North Pole Depot
description: to Crossrail & North Pole Depots
miles: 2
chains: 6
@@ -143,7 +142,7 @@ routeDetail:
name: Old Oak Common East
diverges: left
direction: up
destination: Crossrail Depot
description: to Crossrail Depot
miles: 2
chains: 62
@@ -151,7 +150,7 @@ routeDetail:
name: Old Oak Common West
diverges: left
direction: up
destination: Out of Use for HS2 Works
description: Out of Use for HS2 Works
miles: 3
chains: 20
@@ -173,7 +172,7 @@ routeDetail:
name: Friars Junction
diverges: left
direction: up
destination: Out of Use for HS2 Works
description: Out of Use for HS2 Works
miles: 3
chains: 53
@@ -195,14 +194,14 @@ routeDetail:
- type: signallerChange
from: TVSC Paddington WS
to: TVSC Acton WS
miles: 300
chains: 3000
miles: 3
chains: 80
- type: junction
name: Acton East Junction
diverges: left
direction: up
destination: Up/Dn Poplar to Acton Wells Jn
description: Up/Dn Poplar to Acton Wells Jn
miles: 4
chains: 7
@@ -216,6 +215,7 @@ routeDetail:
- type: station
name: Acton Main Line
description: Relief Lines only
miles: 4
chains: 21
@@ -249,6 +249,7 @@ routeDetail:
- type: station
name: Ealing Broadway
description: Shared with District & Central Lines
miles: 5
chains: 56
@@ -259,15 +260,19 @@ routeDetail:
miles: 5
chains: 61
- type: bridge
name: Spring Bridge Road
position: over
category: minorRoad
miles: 5
chains: 68
- type: tunnel
name: Spring Bridge Road Car Park Tunnel
starts:
tunnelType: whole
length: 0mi 121yd
miles: 5
chains: 70
ends:
miles: 5
chains: 76
lengthYards: 121
chains: 73
- type: bridge
name: Longfield Avenue
@@ -293,6 +298,7 @@ routeDetail:
- type: station
name: West Ealing
description: Relief Lines only with Bay
miles: 6
chains: 46
@@ -300,7 +306,7 @@ routeDetail:
name: West Ealing Junction
diverges: left
direction: down
destination: Dn/Up Greenford to Greenford & West Ealing Sidings
description: Dn/Up Greenford to Greenford & West Ealing Sidings
miles: 6
chains: 54
@@ -315,7 +321,7 @@ routeDetail:
name: Hanwell Junction
diverges: left
direction: up
destination: Dn/Up Loop to Greenford & West Ealing Sidings
description: Dn/Up Loop to Greenford & West Ealing Sidings
miles: 7
chains: 19
@@ -328,15 +334,15 @@ routeDetail:
name: Hanwell Viaduct
position: under
category: waterway
crosses: River Brent
description: River Brent
miles: 7
chains: 6
- type: signallerChange
from: TVSC Acton WS
to: TVSC Hayes WS
miles: 300
chains: 4000
miles: 7
chains: 35
- type: bridge
name: Wharncliffe Viaduct
@@ -347,7 +353,7 @@ routeDetail:
- type: bridge
name: Iron Bridge
crosses: Uxbridge Road
description: Uxbridge Road
position: under
category: aroad
roadName: A4020
@@ -360,11 +366,25 @@ routeDetail:
miles: 8
chains: 20
- type: bridge
position: under
category: foot
name: Lyndhurst Avenue Subway
miles: 8
chains: 29
- type: bridge
position: under
category: foot
name: Church Subway
miles: 8
chains: 46
- type: junction
name: Southall East Junction
diverges: right
direction: up
destination: Brentford Waste Terminal
description: Brentford Waste Terminal & Southall Depot
miles: 8
chains: 62
@@ -390,6 +410,7 @@ routeDetail:
- type: crossovers
name: Southall West Junction
description: Southall Sidings Diverge
miles: 9
chains: 70
@@ -402,6 +423,7 @@ routeDetail:
- type: bridge
name: Grand Union Canal
description: Paddington Branch
position: under
category: waterway
miles: 10
@@ -428,8 +450,16 @@ routeDetail:
miles: 10
chains: 32
- type: bridge
position: under
category: waterway
name: Grand Union Canal
miles: 10
chains: 58
- type: station
name: Hayes & Harlington
description: East facing Bay
miles: 10
chains: 71
@@ -446,7 +476,7 @@ routeDetail:
direction: down
miles: 11
chains: 13
destination: Heathrow Airport
description: Heathrow Airport
- type: bridge
name: New Dawley Road
@@ -483,24 +513,39 @@ routeDetail:
- type: station
name: West Drayton
description: Platform 5 on West Drayton Loop
miles: 13
chains: 17
- type: bridge
name: Station Road
positon: under
category: minorRoad
miles: 12
chains: 56
- type: junction
name: West Drayton Junction
diverges: left
direction: down
destination: Colnbrook Freight (For Heathrow)
description: Colnbrook Freight (near Heathrow)
miles: 13
chains: 31
- type: bridge
name: River Freys
position: under
category: waterway
miles: 13
chains: 37
- type: crossovers
name: West Drayton West
miles: 13
chains: 50
- type: bridge
name: Coinbrook Branch
name: Colnbrook Branch
position: under
category: rail
miles: 13
@@ -528,16 +573,26 @@ routeDetail:
chains: 10
- type: bridge
# name: M25 Motorway
name: London Orbital Motorway
position: over
category: motorway
roadName: M25
miles: 14
chains: 41
- type: signallerChange
from: TVSC Hayes WS
to: TVSC Slough WS
miles: 14
chains: 45
- type: loop
position: left
name: Up Iver loop
elecLoop: none
description: Part electrified
miles: 14
chains: 50
- type: bridge
name: Thorney Lane South
@@ -551,12 +606,6 @@ routeDetail:
miles: 14
chains: 60
- type: signallerChange
from: TVSC Hayes WS
to: TVSC Slough WS
miles: 300
chains: 5000
- type: bridge
name: Market Lane
position: under
@@ -574,11 +623,18 @@ routeDetail:
- type: junction
name: Langley GF
diverges: left
destination: Langley Sidings
description: Langley Sidings
direction: up
miles: 15
chains: 76
- type: bridge
position: under
category: foot
name: Nash's Subway
miles: 15
chains: 76
- type: station
name: Langley
miles: 16
@@ -615,6 +671,7 @@ routeDetail:
- type: crossovers
name: Dolphin Junction
description: Multiple crossovers
miles: 17
chains: 20
@@ -635,6 +692,7 @@ routeDetail:
- type: station
name: Slough
description: Change for Windsor
miles: 18
chains: 36
@@ -649,7 +707,7 @@ routeDetail:
name: Windsor Branch Junction
diverges: right
direction: down
destination: Windsor Branch
description: Windsor Branch from platforms 1 & 2 Only
miles: 18
chains: 44
@@ -709,6 +767,7 @@ routeDetail:
- type: station
name: Burnham
description: Relief Lines only
miles: 20
chains: 77
@@ -742,6 +801,7 @@ routeDetail:
- type: station
name: Taplow
description: Main line platforms too low for service stops
miles: 22
chains: 39
@@ -818,7 +878,7 @@ routeDetail:
name: Marlow Branch
diverges: left
direction: down
destination: Bourne End & Marlow
description: Bourne End & Marlow, from Platform 5 only
miles: 24
chains: 25
@@ -826,7 +886,7 @@ routeDetail:
name: Maidenhead Stabling Sidings
diverges: left
direction: down
destination: Crossrail Sidings
description: Crossrail Sidings
miles: 24
chains: 40
@@ -883,13 +943,13 @@ routeDetail:
- type: signallerChange
from: TVSC Slough WS
to: TVSC Twyford WS
miles: 300
chains: 6000
miles: 27
chains: 45
- type: bridge
name: Pipeline
position: over
category: pipes
category: pipeline
miles: 27
chains: 60
@@ -949,6 +1009,7 @@ routeDetail:
- type: crossovers
name: Twyford East
description: Crossover from Down Relief to Up Relief
miles: 30
chains: 68
@@ -966,10 +1027,9 @@ routeDetail:
chains: 1
- type: junction
name: Henley Branch Junction
diverges: left
direction: down
destination: Henley-on-Thames
description: Henley-on-Thames from Platform 4 only
miles: 31
chains: 4
@@ -982,16 +1042,16 @@ routeDetail:
- type: bridge
name: Seven Arch Viaduct
crosses: River Loddon
description: River Loddon
position: under
category: waterway
miles: 31
chains: 20
- type: bridge
name:
name: Footpath
position: under
category:
category: foot
miles: 31
chains: 30
@@ -1046,7 +1106,7 @@ routeDetail:
- type: bridge
name: Gas Pipeline
position: over
category: pipes
category: pipeline
miles: 33
chains: 71
@@ -1060,17 +1120,24 @@ routeDetail:
- type: loop
position: left
name: Kennet Passenger Loop
description: Between Up/Dn Relief
miles: 34
chains: 48
- type: bridge
name: Broken Brow
position: under
category: motorway
roadName: A329(M)
category: aroad
roadName: A3290
miles: 34
chains: 50
- type: signallerChange
from: TVSC Twyford WS
to: TVSC Reading WS
miles: 34
chains: 70
- type: bridge
name: River Kennet
position: under
@@ -1078,22 +1145,31 @@ routeDetail:
miles: 34
chains: 77
- type: signallerChange
from: TVSC Twyford WS
to: TVSC Reading WS
miles: 300
chains: 7000
- type: crossovers
name: Kennet Bridge Junction
miles: 35
chains: 10
- type: bridge
name: Huntley & Palmers Tunnel
description: Disused
position: under
category: foot
miles: 35
chains: 28
- type: junction
name: Reading New Junction
diverges: right
direction: up
destination: Southern Lines
description: to Southern Lines (Waterloo/Guildford)
miles: 35
chains: 40
- type: bridge
position: under
category: rail
name: Low Level Tunnel
miles: 35
chains: 40
@@ -1101,7 +1177,7 @@ routeDetail:
name: Reading East Junction
diverges: left
direction: up
destination: Southern Lines
description: to Southern Lines (Waterloo/Guildford)
miles: 35
chains: 61
@@ -1116,3 +1192,44 @@ routeDetail:
name: Reading
miles: 35
chains: 78
- type: bridge
name: Caversham Road
position: under
category: minorRoad
miles: 35
chains: 11
- type: junction
diverges: right
direction: down
name: Westbury Line Junction
description: to Oxford Road Jn
miles: 36
chains: 17
- type: junction
diverges: right
direction: down
name: Caversham Road Junction
description: Reading Feeder Main/Relief diverge and pass under Reading Viaduct to Oxford Rd Jn
miles: 36
chains: 22
- type: crossovers
name: Reading High Level Junction
description: Down Reading Festival Connects to Down Main
miles: 36
chains: 47
- type: junction
diverges: right
direction: up
name: Reading West Junction
description: to Oxford Road Junction (From relief lines only)
miles: 37
chains: 17
- type: continues
routeName: Reading West Jn - Bristol TM
routeId: "0002"