Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
29 commits
Select commit Hold shift + click to select a range
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 6 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -13,11 +13,15 @@ https://ts-metro.netlify.app

### Desktop view

[![tsMetro screenshot for desktop](./docs/imgs/tsmetro-desktop.png)](https://ts-metro.netlify.app)
<p align="center">
<img alt="tsMetro screenshot for desktop" src="./docs/imgs/tsmetro-desktop.png">
</p>

### Mobile view

[![tsMetro screenshot for mobile](./docs/imgs/tsmetro-mobile.png)](https://ts-metro.netlify.app)
<p align="center">
<img alt="tsMetro screenshot for mobile" src="./docs/imgs/tsmetro-mobile.png" width="50%">
</p>

## Project setup
```
Expand Down
Binary file modified docs/imgs/tsmetro-desktop.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file modified docs/imgs/tsmetro-mobile.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
4 changes: 2 additions & 2 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

6 changes: 3 additions & 3 deletions package.json
Original file line number Diff line number Diff line change
@@ -1,12 +1,12 @@
{
"name": "ts-metro",
"version": "1.5.4",
"version": "1.6.0",
"type": "module",
"scripts": {
"dev": "vite",
"build": "run-p format lint type-check \"build-only {@}\" --",
"build": "run-p test:unit format lint type-check \"build-only {@}\" --",
"preview": "vite preview",
"test:unit": "vitest",
"test:unit": "vitest run --reporter verbose",
"build-only": "vite build",
"type-check": "vue-tsc --build",
"lint": "eslint . --fix",
Expand Down
38 changes: 38 additions & 0 deletions src/components/LineBadge.vue
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
<template lang="pug">
span.font-medium.text-xs.text-center.rounded.py-1.px-2(:style="badgeStyle") {{ content }}
</template>

<script lang="ts">
import { defineComponent } from 'vue'

export default defineComponent({
name: 'LineBadge',
props: {
bgColor: {
type: String,
required: true,
},
textColor: {
type: String,
required: true,
},
borderColor: {
type: String,
required: true,
},
content: {
type: String,
required: true,
},
},
computed: {
badgeStyle() {
return {
backgroundColor: this.bgColor,
color: this.textColor,
border: `1px solid ${this.borderColor}`,
}
},
},
})
</script>
14 changes: 8 additions & 6 deletions src/components/MetroMadrid.vue
Original file line number Diff line number Diff line change
Expand Up @@ -62,7 +62,7 @@ export default defineComponent({
stations: new Array<Station>(),
selectedOrigin: '',
selectedDestiny: '',
shortestPath: new Array<string>(),
shortestPath: new Array<any>(),
linesConfig: new Map<any, any>(),
distance: 0,
clicked: false,
Expand Down Expand Up @@ -104,15 +104,17 @@ export default defineComponent({
this.clicked = true
this.isLoading = true
const stationOrigin: Station = this.metro.getStationById(this.selectedOrigin)
const stationDestiny: Station = this.metro.getStationById(this.selectedDestiny)
const [path, distance] = this.metro.getShortestPath(stationOrigin, stationDestiny)
const stationDestination: Station = this.metro.getStationById(this.selectedDestiny)
const { path, distance } = this.metro.getShortestPath(stationOrigin, stationDestination)
this.distance = distance
this.shortestPath = path
this.shortestPath = path.map((step: any) => ({
station: step.station,
segment: step.segment,
transfer: step.transfer,
}))
this.isLoading = false
}
},
},
})
</script>

<style scoped></style>
68 changes: 60 additions & 8 deletions src/components/StationItem.vue
Original file line number Diff line number Diff line change
@@ -1,24 +1,76 @@
<template lang="pug">
.flex.flex-col.items-center.w-full
.flex.bg-red-50.px-2.py-2.border-l-4.border-r-4.border.border-red-600.shadow-xl.rounded-xl.justify-between.w-full(class="md:w-3/4")
.flex.px-2.py-2.border-l-4.border-r-4.border.shadow-xl.justify-between.w-full(class="md:w-3/4", :style="borderStyle")
.flex-row.flex.mr-4
span.text-left.antialiased.text-gray-800 {{station.name}}
.flex.items-center.flex.flex-nowrap.overflow-auto
template(v-for="line in station.getLines()")
span.font-medium.text-xs.text-center.rounded.mr-1.py-1.px-2(class="last:mr-0" :style="[{'background-color': lines.get(line).bgColor}, {'color': lines.get(line).textColor}, {'border': `1px solid ${lines.get(line).borderColor}`}]") {{line}}
SeparatorIcon.rotate-90.w-4.fill-current.text-blue-400.m-2(class="last:display-none", v-if="!isLast")
LineBadge(v-if="!transfer"
:bgColor="lines.get(currentLine).bgColor"
:textColor="lines.get(currentLine).textColor"
:borderColor="lines.get(currentLine).borderColor"
:content="currentLine")
.flex.items-center(v-if="transfer")
span.mr-2.text-xs.text-center.rounded.py-1 De
LineBadge.mr-2(
:bgColor="lines.get(transfer.fromLine).bgColor"
:textColor="lines.get(transfer.fromLine).textColor"
:borderColor="lines.get(transfer.fromLine).borderColor"
:content="transfer.fromLine")
span.mr-2.text-xs.text-center.rounded.py-1 a
LineBadge(
:bgColor="lines.get(transfer.toLine).bgColor"
:textColor="lines.get(transfer.toLine).textColor"
:borderColor="lines.get(transfer.toLine).borderColor"
:content="transfer.toLine")
</template>

<script lang="ts">
import { defineComponent } from 'vue'

import SeparatorIcon from '@/components/SeparatorIcon.vue'
import LineBadge from '@/components/LineBadge.vue'

export default defineComponent({
name: 'StationItem',
props: ['station', 'lines', 'isLast'],
components: {
SeparatorIcon,
LineBadge,
},
props: ['station', 'lines', 'isLast', 'transfer', 'currentLine'],
computed: {
borderStyle() {
if (this.transfer) {
let fromColor, toColor

const fromLine = this.lines.get(this.transfer.fromLine)

const toLine = this.lines.get(this.transfer.toLine)
if (this.transfer.fromLine.startsWith('ML') || this.transfer.fromLine.startsWith('R')) {
fromColor = fromLine.borderColor
} else {
fromColor = fromLine.bgColor
}

if (this.transfer.toLine.startsWith('ML') || this.transfer.toLine.startsWith('R')) {
toColor = toLine.borderColor
} else {
toColor = toLine.bgColor
}

return {
borderImage: `linear-gradient(to bottom, ${fromColor}, ${toColor}) 1`,
}
}

let currentColor

if (this.currentLine.startsWith('ML') || this.currentLine.startsWith('R')) {
currentColor = this.lines.get(this.currentLine).borderColor
} else {
currentColor = this.lines.get(this.currentLine).bgColor
Comment thread
jiep marked this conversation as resolved.
}

return {
borderColor: currentColor,
}
},
},
})
</script>
7 changes: 6 additions & 1 deletion src/components/StationList.vue
Original file line number Diff line number Diff line change
@@ -1,6 +1,11 @@
<template lang="pug">
.flex.flex-col.text-center.items-center(v-for="(station, i) in stations")
StationItem(class="w-full" :station="station" :lines="lines" :is-last="stations.length - 1 === i")
StationItem(
:transfer="station.transfer"
:station="station.station"
:lines="lines"
:is-last="stations.length - 1 === i"
:currentLine="station.segment?.line")
</template>

<script lang="ts">
Expand Down
79 changes: 70 additions & 9 deletions src/lib/model/MetroMadrid.ts
Original file line number Diff line number Diff line change
Expand Up @@ -17,15 +17,76 @@ export default class MetroMadrid extends Metro {
})
}

public getShortestPath(source: Station, destination: Station): Array<any> {
let stationsAndDistance: Array<any> = []
if (source.getId() !== destination.getId()) {
stationsAndDistance = this.distancesGraph.shortestPath(source.getId(), destination.getId())
const [stations, distance] = stationsAndDistance
const a: Array<Station> = stations.map((stationId: number) => this.getStationById(stationId))
return [a, distance]
} else {
return [source, 0]
public getShortestPath(
source: Station,
destination: Station,
): {
path: Array<{
station: Station
segment: { line: string; from: Station; to: Station } | null
transfer: { fromLine: string; toLine: string } | null
}>
distance: number
} {
if (source.getId() === destination.getId()) {
return {
path: [{ station: source, segment: null, transfer: null }],
distance: 0,
}
}

const [stationIds, distance] = this.distancesGraph.shortestPath(
source.getId(),
destination.getId(),
)
const path: Array<{
station: Station
segment: { line: string; from: Station; to: Station } | null
transfer: { fromLine: string; toLine: string } | null
}> = []

let currentLine: string | null = null

for (let i = 0; i < stationIds.length; i++) {
const currentStation = this.getStationById(stationIds[i])
let transferInfo: { fromLine: string; toLine: string } | null = null

if (i < stationIds.length - 1) {
const nextStation = this.getStationById(stationIds[i + 1])
const commonLines = this.findCommonLines(currentStation, nextStation)
if (commonLines.length === 0) {
throw new Error(
`No line connects stations ${currentStation.getName()} and ${nextStation.getName()}`,
)
}

const line = commonLines[0]

if (currentLine && currentLine !== line) {
transferInfo = { fromLine: currentLine, toLine: line }
}

currentLine = line
path.push({
station: currentStation,
segment: { line, from: currentStation, to: nextStation },
transfer: transferInfo,
})
} else {
path.push({
station: currentStation,
segment: { line: currentLine!, from: currentStation, to: currentStation },
Comment thread
jiep marked this conversation as resolved.
Comment thread
jiep marked this conversation as resolved.
Comment thread
jiep marked this conversation as resolved.
transfer: null,
})
}
}

return { path, distance }
}

private findCommonLines(station1: Station, station2: Station): Array<string> {
const lines1 = station1.getLines()
const lines2 = station2.getLines()
return lines1.filter((line) => lines2.includes(line))
}
}
75 changes: 54 additions & 21 deletions test/model/Line.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,40 +8,73 @@ describe('Line', () => {
describe('Constructor', () => {
it('should create a new `Line`', () => {
line = new Line('1', '#FFFFFF', '#AAAAAA', '#123456')
const name = line.getName()
const bgColor = line.getBgColor()
const textColor = line.getTextColor()
const borderColor = line.getBorderColor()
expect(name).to.equal('1')
expect(bgColor).to.equal('#FFFFFF')
expect(textColor).to.equal('#AAAAAA')
expect(borderColor).to.equal('#123456')
expect(line).to.be.an.instanceOf(Line)
expect(line.name).to.equal('1')
expect(line.bgColor).to.equal('#FFFFFF')
expect(line.textColor).to.equal('#AAAAAA')
expect(line.borderColor).to.equal('#123456')
})
})

describe('Equality', () => {
it('should consider two lines with the same properties as equal', () => {
const line1 = new Line('1', '#FFFFFF', '#AAAAAA', '#123456')
const line2 = new Line('1', '#FFFFFF', '#AAAAAA', '#123456')
expect(line1).to.eql(line2)
})

it('should consider two lines with different properties as not equal', () => {
const line1 = new Line('1', '#FFFFFF', '#AAAAAA', '#123456')
const line2 = new Line('2', '#000000', '#BBBBBB', '#654321')
expect(line1).to.not.eql(line2)
})
})

describe('Getters', () => {
beforeEach(function () {
beforeEach(() => {
line = new Line('1', '#FFFFFF', '#AAAAAA', '#123456')
})

it('should return the correct name', () => {
expect(line.name).to.equal('1')
})

it('should return the correct background color', () => {
expect(line.bgColor).to.equal('#FFFFFF')
})

it('should return the correct text color', () => {
expect(line.textColor).to.equal('#AAAAAA')
})

it('should return the correct border color', () => {
expect(line.borderColor).to.equal('#123456')
})
})

describe('Setters', () => {
beforeEach(() => {
line = new Line('1', '#FFFFFF', '#AAAAAA', '#123456')
})

it('should return the correct `name`', () => {
const name: string = line.getName()
expect(name).to.equal('1')
it('should allow changing the name', () => {
line.name = '2'
expect(line.name).to.equal('2')
})

it('should return the correct `background color`', () => {
const bgColor: string = line.getBgColor()
expect(bgColor).to.equal('#FFFFFF')
it('should allow changing the background color', () => {
line.bgColor = '#000000'
expect(line.bgColor).to.equal('#000000')
})

it('should return the correct `text color`', () => {
const textColor: string = line.getTextColor()
expect(textColor).to.equal('#AAAAAA')
it('should allow changing the text color', () => {
line.textColor = '#BBBBBB'
expect(line.textColor).to.equal('#BBBBBB')
})

it('should return the correct `border color`', () => {
const borderColor: string = line.getBorderColor()
expect(borderColor).to.equal('#123456')
it('should allow changing the border color', () => {
line.borderColor = '#654321'
expect(line.borderColor).to.equal('#654321')
})
})
})
Loading