new stuff

This commit is contained in:
cjdenio committed 2024-10-08 22:00:12 -04:00
1 parent eeecd72331
commit 6f9de5aa9f
10 files changed
+3447 -68

No files matched your search

+8 -2
View File
@@ -84,7 +84,7 @@ export function stepsValidForStationPair(steps, stationA, stationB) {
if (steps[steps.length - 1].station != stationB)
return [
false,
`Route doesn't end at ${agency.stations[stationB].stop_name}.`,
[`Route doesn't end at ${agency.stations[stationB].stop_name}.`],
];
let stops = 0;
@@ -99,7 +99,13 @@ export function stepsValidForStationPair(steps, stationA, stationB) {
if (!possible) {
return [
false,
`${steps[i].line} doesn't serve ${agency.stations[err].stop_name}`,
new Array(steps.length).fill(
`${agency.routes[steps[i].line].route_long_name} doesn't serve ${
agency.stations[err].stop_name
}`,
i,
i + 1
),
];
}
stops += _stops;
+38 -12
View File
@@ -1,5 +1,5 @@
<script>
import { onMount, createEventDispatcher } from "svelte";
import { onMount, createEventDispatcher, tick } from "svelte";
import agency, { minStops, randomStationPair, stepsValidForStationPair } from "../agency"
import MbtaLine from "./MbtaLine.svelte";
import RouteBuilder from "./RouteBuilder.svelte";
@@ -17,52 +17,74 @@
let to
let points = 0
let errors = []
function setStationPair() {
let pointFlourish
let pointCounter
let stationsElement
async function setStationPair() {
const stations = randomStationPair()
from = stations[0]
to = stations[1]
await tick()
gsap.from(stationsElement, { opacity: 0, scale: 0.9 })
}
onMount(() => {
setStationPair()
})
let pointFlourish
let pointCounter
let disabled = false
async function submit() {
if(disabled) return
disabled = true
if(route[route.length - 1].station != to) {
return alert(`Oops, your route doesn't end at ${agency.stations[to].stop_name}!`)
}
const [valid, err, stops] = (stepsValidForStationPair(route, from, to))
if(!valid) {
gsap.to(pointCounter, {
await gsap.to(pointCounter, {
keyframes: {
rotate: [0, -10, 10, -10, 10, -10, 10, -10, 10, 0]
}
})
}).then()
errors = err
} else if(stops > minStops(from, to)) {
await addPoints(1)
next()
} else {
await addPoints(2)
next()
}
}
if(question >= 9) {
function next() {
if(question >= questionCount - 1) {
window.umami?.track("Completed quiz")
dispatch("done", points)
return
}
question++
route = []
errors = []
setStationPair()
disabled = false
}
async function addPoints(p) {
points += p
pointFlourish.innerText = `+${p}`
gsap.to(pointFlourish, {x: -40, y: -50, rotate: -30, scale: 2, opacity: 0, duration: 1, startAt: {opacity: 1, y: 0, x: 0, scale: 1, rotate: 0}})
await gsap.to(pointFlourish, {x: -40, y: -50, rotate: -30, scale: 2, opacity: 0, duration: 1, startAt: {opacity: 1, y: 0, x: 0, scale: 1, rotate: 0}}).then()
}
</script>
@@ -73,7 +95,7 @@
</div>
{#if from && to}
<h3 class="text-3xl">
<h3 class="text-3xl inline-block" bind:this={stationsElement}>
<span class="inline-flex items-center justify-center gap-2">
<span class="font-bold">{agency.stations[from].stop_name}</span>
{#each agency.stations[from].routes as line}
@@ -94,8 +116,12 @@
{/if}
</div>
<RouteBuilder lines={agency.routes} stations={agency.stations} origin={agency.stations[from]?.stop_name} bind:route />
<RouteBuilder {errors} lines={agency.routes} stations={agency.stations} origin={agency.stations[from]?.stop_name} showRemovalButton={!disabled} bind:route />
<button class="text-md border border-blue-500 text-blue-500 font-bold rounded-lg px-5 py-1 uppercase cursor-pointer transition-colors hover:bg-blue-50" on:click={submit} class:opacity-50={route.length == 0} disabled={route.length == 0}>
Submit
<button class="text-md border border-blue-500 text-blue-500 font-bold rounded-lg px-5 py-1 uppercase cursor-pointer transition-colors hover:bg-blue-50" on:click={() => errors.length == 0 ? submit() : next()} class:opacity-50={route.length == 0} disabled={route.length == 0}>
{#if errors.length == 0}
Submit
{:else}
Next
{/if}
</button>
+9
View File
@@ -1,6 +1,7 @@
<script>
import Game from "./Game.svelte";
import screenshot from "../screenshot.png"
import Route from "./Route.svelte";
let page = "welcome"
let score = 0
@@ -28,6 +29,14 @@
{/if}
<div class="flex flex-col items-center justify-center">
<div class="mx-auto">
<Route origin="Sullivan Square" steps={[
{ line: "Orange", station: "place-north" },
{ line: "Green-D", station: "place-pktrm" },
{ line: "Red", station: "place-knncl" },
]} />
</div>
<div class="inline-block relative text-left mb-5">
<h1 class="font-black text-5xl">The Train Quiz</h1>
<div class="max-w-72">
+69
View File
@@ -0,0 +1,69 @@
<script>
import MbtaLine from "./MbtaLine.svelte";
import agency from "../agency"
import { createEventDispatcher } from "svelte";
const dispatch = createEventDispatcher()
export let steps = [];
export let origin;
export let showRemovalButton = false;
export let errors = []
</script>
<ul class="w-full mb-4 empty:mb-0">
<li class="relative font-bold">{origin}</li>
{#each steps as step, index}
<li class="relative flex items-center">
<MbtaLine name={step.line} />
<span>
to
<span class="font-bold relative">
{#if errors[index]}
<div class="absolute bottom-full left-full text-nowrap border border-red-500 text-red-500 bg-white/90 p-3 rounded-lg rounded-bl-none z-40 animate-error origin-bottom-left">
{errors[index]}
</div>
{/if}
{agency.stations[step.station].stop_name}
</span>
</span>
{#if showRemovalButton}
<button class="ml-auto text-gray-500" on:click={() => dispatch("remove", index)}>x</button>
{/if}
</li>
{/each}
</ul>
<style>
li {
@apply pl-5;
}
li:before {
content: "";
width: 10px;
height: 10px;
@apply bg-white rounded-full ring ring-gray-800;
display: block;
position: absolute;
top: calc(50% - 5px);
left: 0;
z-index: 5;
}
li:after {
content: "";
height: 100%;
width: 4px;
@apply bg-gray-800;
position: absolute;
left: 3px;
}
li:first-of-type::after {
@apply rounded-t-full;
}
li:last-of-type::after {
@apply rounded-b-full;
}
</style>
+6 -46
View File
@@ -1,12 +1,14 @@
<script>
import { onMount } from "svelte";
import MbtaLine from "./MbtaLine.svelte";
import Route from "./Route.svelte";
export let route = []
export let errors = []
export let lines
export let stations
export let origin
export let showRemovalButton = true
let selectedLine = ""
let selectedStation = ""
@@ -34,20 +36,9 @@
</script>
<div class="p-5 rounded-lg mb-5">
<ul class="w-full mb-4 empty:mb-0">
<li class="relative font-bold">{origin}</li>
{#each route as step, index }
<li class="relative flex items-center">
<MbtaLine name={step.line} />
<span>
to
<span class="font-bold">{stations[step.station].stop_name}</span>
</span>
<button class="ml-auto text-gray-500" on:click={() => {route = route.filter((v,idx) => idx != index)}}>x</button>
</li>
{/each}
</ul>
<Route steps={route} {errors} {origin} {showRemovalButton} on:remove={({detail}) => {
route = route.filter((v, index) => index != detail)
}} />
<div class="flex gap-2 items-center">
<form on:submit|preventDefault={() => addStep()}>
@@ -75,37 +66,6 @@
</div>
<style>
li {
@apply pl-5;
}
li:before {
content: "";
width: 10px;
height: 10px;
@apply bg-white rounded-full ring ring-gray-800;
display: block;
position: absolute;
top: calc(50% - 5px);
left: 0;
z-index: 5;
}
li:after {
content: "";
height: 100%;
width: 4px;
@apply bg-gray-800;
position: absolute;
left: 3px;
}
li:first-of-type::after {
@apply rounded-t-full;
}
li:last-of-type::after {
@apply rounded-b-full;
}
select {
@apply border border-blue-500 rounded-md;
}
+14 -2
View File
@@ -25,8 +25,12 @@ import screenshot from "../screenshot.png";
<p
class="fixed bottom-0 left-0 text-gray-400 transition-transform translate-y-3 hover:translate-y-0 hover:translate-x-2 cursor-default"
>
<a href="https://calebden.io" class="underline" target="_blank">caleb</a> made
this
<a href="https://calebden.io" class="underline" target="_blank">Caleb</a> made
this &middot; and it's on <a
href="https://github.com/cjdenio/train-quiz"
class="underline"
target="_blank">GitHub</a
>
</p>
<p class="fixed bottom-1 right-2 text-gray-400">
@@ -36,5 +40,13 @@ import screenshot from "../screenshot.png";
target="_blank">MBTA</a
>
</p>
<script>
import Honeybadger from "@honeybadger-io/js";
Honeybadger.configure({
apiKey: "hbp_kMocExYws1yKlIKXs0TkQzbAGmDpqJ2kz24F",
environment: import.meta.env.MODE,
});
</script>
</body>
</html>