Compare commits
No commits in common. "1672d4de9489175face703bc013ab048c5d222e5" and "2491560cd233fc7036bbda660a11a0e23e725ecc" have entirely different histories.
1672d4de94
...
2491560cd2
|
@ -1,23 +0,0 @@
|
|||
pipeline {
|
||||
agent any
|
||||
environment {
|
||||
PATH = "/var/lib/jenkins/bin:/var/lib/jenkins/.nvm/versions/node/v20.9.0/bin:${env.PATH}"
|
||||
}
|
||||
stages {
|
||||
stage('Install deps') {
|
||||
steps {
|
||||
sh 'pnpm i'
|
||||
}
|
||||
}
|
||||
stage('Build bundle') {
|
||||
steps {
|
||||
sh 'pnpm build'
|
||||
}
|
||||
}
|
||||
stage('Deploy') {
|
||||
steps {
|
||||
sh 'cp -r ./dist/* /var/www/combi/'
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -6,13 +6,5 @@
|
|||
"color": "#ea4fb2",
|
||||
"hover_bg": "#ea4fb2",
|
||||
"hover_on_bg": "white"
|
||||
},
|
||||
{
|
||||
"id": 2,
|
||||
"name": "2",
|
||||
"district": "Socabaya",
|
||||
"color": "blue",
|
||||
"hover_bg": "blue",
|
||||
"hover_on_bg": "white"
|
||||
}
|
||||
]
|
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
12
src/App.tsx
12
src/App.tsx
|
@ -1,19 +1,19 @@
|
|||
import "leaflet/dist/leaflet.css";
|
||||
import { Route, HashRouter } from "@solidjs/router";
|
||||
import { Editor } from "./pages/Editor";
|
||||
import { Index } from "./pages/Index";
|
||||
import { Route, Router } from "@solidjs/router";
|
||||
import { Editor } from "./pages/Editor";
|
||||
import { Index2 } from "./pages/Index2";
|
||||
import { Arrow } from "./pages/Arrow";
|
||||
import { IndexMobile } from "./pages/IndexMobile";
|
||||
|
||||
export default function() {
|
||||
return (
|
||||
<>
|
||||
<HashRouter>
|
||||
<Router>
|
||||
<Route path="/" component={Index} />
|
||||
<Route path="/mobile" component={IndexMobile} />
|
||||
<Route path="/new" component={Index2} />
|
||||
<Route path="/editor" component={Editor} />
|
||||
<Route path="/arrow" component={Arrow} />
|
||||
</HashRouter>
|
||||
</Router>
|
||||
</>
|
||||
);
|
||||
}
|
||||
|
|
|
@ -1,45 +1,39 @@
|
|||
import L from "leaflet";
|
||||
import { createEffect, createResource, createSignal, For, onMount, Suspense } from "solid-js";
|
||||
import { Map, map, polyline, tileLayer } from "leaflet";
|
||||
import { createEffect, createResource, For, onMount, Suspense } from "solid-js";
|
||||
import { Line, RouteWrapper, Route, LineWrapper, PointsWrapper } from "../types";
|
||||
import { LineSegmentsIcon } from "../icons/LineSegmentsIcon";
|
||||
import { Line, Lines, Route, Routes } from "../new_types";
|
||||
|
||||
let global_map: L.Map | null = null;
|
||||
const [global_count, set_global_count] = createSignal(0);
|
||||
let g_map: Map | null = null;
|
||||
|
||||
export function Index() {
|
||||
const container = <div class="md:h-[98vh] h-[65vh] md:rounded-lg dark:opacity-60" />;
|
||||
const container = <div class="h-[98vh] rounded-lg dark:opacity-60" />;
|
||||
|
||||
onMount(() => {
|
||||
// Detect screen size and ratio,
|
||||
// and redirect to mobile page if neccesary
|
||||
if (window.matchMedia("only screen and (max-width: 760px)").matches) {
|
||||
window.location.replace("/#/mobile");
|
||||
return;
|
||||
}
|
||||
|
||||
global_map = L.map(container as HTMLElement)
|
||||
const l_map = map(container as HTMLElement)
|
||||
.setView([-16.40171, -71.53040], 13);
|
||||
g_map = l_map;
|
||||
|
||||
L.tileLayer("/tiles/{z}/{x}/{y}.jpg", {
|
||||
tileLayer("/tiles/{z}/{x}/{y}.jpg", {
|
||||
maxZoom: 17,
|
||||
minZoom: 12,
|
||||
attribution: "Map data © <a href=\"http://www.openstreetmap.org/copyright\">OpenStreetMap</a>",
|
||||
}).addTo(global_map);
|
||||
attribution: "© Map data <a href=\"http://www.openstreetmap.org/copyright\">OpenStreetMap</a>",
|
||||
}).addTo(l_map);
|
||||
});
|
||||
|
||||
return (
|
||||
<div class="grid md:grid-cols-[15rem_auto] md:grid-rows-none grid-rows-[65vh_35vh]">
|
||||
<div class="md:h-screen overflow-scroll">
|
||||
<div class="grid grid-cols-[15rem_auto]">
|
||||
<div class="h-screen overflow-scroll">
|
||||
<h1 class="text-c-primary text-center font-bold text-2xl py-4">AQP combi</h1>
|
||||
|
||||
<h2 class="bg-c-primary text-white py-2 px-2 font-bold text-lg">
|
||||
Lineas
|
||||
</h2>
|
||||
|
||||
<LinesEl />
|
||||
<Lines />
|
||||
|
||||
</div>
|
||||
<div class="md:py-[0.5vh] md:pr-2">
|
||||
<div class="md:rounded-lg overflow-hidden md:p-1"
|
||||
<div class="py-[0.5vh] pr-2">
|
||||
<div class="rounded-lg overflow-hidden p-1"
|
||||
style="box-shadow: inset 0 0 5px 0px var(--main)"
|
||||
>
|
||||
{container}
|
||||
|
@ -49,17 +43,18 @@ export function Index() {
|
|||
);
|
||||
}
|
||||
|
||||
function LinesEl() {
|
||||
const [linesData] = createResource<Lines>(async() => {
|
||||
const res = await fetch("/n/lines.json");
|
||||
function Lines() {
|
||||
const [lineData] = createResource<LineWrapper>(async() => {
|
||||
const res = await fetch("/data/root.json");
|
||||
if (!res.ok) throw new Error("Error fetching data");
|
||||
return res.json();
|
||||
});
|
||||
|
||||
|
||||
return (
|
||||
<>
|
||||
<Suspense fallback={<div>Cargando...</div>}>
|
||||
<For each={linesData() ?? []}>
|
||||
<For each={lineData()?.data ?? []}>
|
||||
{(l) => <LineEl line={l} />}
|
||||
</For>
|
||||
</Suspense>
|
||||
|
@ -68,161 +63,61 @@ function LinesEl() {
|
|||
}
|
||||
|
||||
function LineEl(props: { line: Line }) {
|
||||
const [routesData] = createResource<Routes>(async() => {
|
||||
const res = await fetch(`/n/routes_${props.line.id}.json`);
|
||||
const [lineRoute] = createResource<RouteWrapper>(async() => {
|
||||
const res = await fetch(`/data/cuenca_${props.line.id_cuenca}.json`);
|
||||
if (!res.ok) throw new Error("Error fetching data");
|
||||
return res.json();
|
||||
});
|
||||
|
||||
return (
|
||||
<div
|
||||
style={`color: ${props.line.color};--hover-bg: ${props.line.hover_bg};--hover-on-bg: ${props.line.hover_on_bg}`}
|
||||
>
|
||||
<div style={`color: ${props.line.color}`}>
|
||||
<LineSegmentsIcon class="px-1" fill={props.line.color} />
|
||||
<span class="px-2" title={props.line.district}>
|
||||
Linea {props.line.name}
|
||||
<span class="px-2">
|
||||
Linea {props.line.name ?? "A"}
|
||||
</span>
|
||||
<Suspense>
|
||||
<For each={routesData() ?? []}>
|
||||
{(r) => (
|
||||
<RouteEl
|
||||
line_name={props.line.name}
|
||||
route={r}
|
||||
color={props.line.color}
|
||||
/>
|
||||
)}
|
||||
<For each={lineRoute()?.data ?? []}>
|
||||
{(r) => <RouteEl route={r} parent_id={props.line.id_cuenca} color={props.line.color} />}
|
||||
</For>
|
||||
</Suspense>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
function RouteEl(props: {
|
||||
line_name: string,
|
||||
route: Route,
|
||||
color: string,
|
||||
}) {
|
||||
const [departure_active, set_departure_active] = createSignal(false);
|
||||
const [return_active, set_return_active] = createSignal(false);
|
||||
const [departure_count, set_departure_count] = createSignal(0);
|
||||
const [return_count, set_return_count] = createSignal(0);
|
||||
|
||||
// Create departure and return polylines
|
||||
const departure_polyline = L.polyline(props.route.departure, { color: props.color });
|
||||
const return_polyline = L.polyline(props.route.return, { color: props.color });
|
||||
|
||||
// Rended the lines into the map
|
||||
createEffect(() => {
|
||||
if (global_count() === 0 || departure_count() > 0) {
|
||||
departure_polyline.addTo(global_map!);
|
||||
} else {
|
||||
departure_polyline.removeFrom(global_map!);
|
||||
}
|
||||
function RouteEl(props: { route: Route, parent_id: number, color: string }) {
|
||||
const [points] = createResource<PointsWrapper>(async() => {
|
||||
const res = await fetch(`/data/cuenca_${props.parent_id}_ruta_${props.route.id_ruta}_ida.json`);
|
||||
if (!res.ok) throw new Error("Error fetching data");
|
||||
return res.json();
|
||||
});
|
||||
createEffect(() => {
|
||||
// if global count === 0, then no route is focused.
|
||||
// in that case, all routes should be rendered
|
||||
if (global_count() === 0 || return_count() > 0) {
|
||||
return_polyline.addTo(global_map!);
|
||||
} else {
|
||||
return_polyline.removeFrom(global_map!);
|
||||
}
|
||||
const [return_points] = createResource<PointsWrapper>(async() => {
|
||||
const res = await fetch(`/data/cuenca_${props.parent_id}_ruta_${props.route.id_ruta}_vuelta.json`);
|
||||
if (!res.ok) throw new Error("Error fetching data");
|
||||
return res.json();
|
||||
});
|
||||
|
||||
const toggle_departure = () => {
|
||||
const currently_active = departure_active();
|
||||
if (currently_active) {
|
||||
set_global_count((c) => c - 1);
|
||||
set_departure_count((c) => c - 1);
|
||||
set_departure_active(false);
|
||||
} else {
|
||||
set_global_count((c) => c + 1);
|
||||
set_departure_count((c) => c + 1);
|
||||
set_departure_active(true);
|
||||
}
|
||||
};
|
||||
const toggle_return = () => {
|
||||
const currently_active = return_active();
|
||||
if (currently_active) {
|
||||
set_global_count((c) => c - 1);
|
||||
set_return_count((c) => c - 1);
|
||||
set_return_active(false);
|
||||
} else {
|
||||
set_global_count((c) => c + 1);
|
||||
set_return_count((c) => c + 1);
|
||||
set_return_active(true);
|
||||
}
|
||||
};
|
||||
createEffect(() => {
|
||||
// Render the dots into the map
|
||||
if (!points()) return;
|
||||
const coords = points()!.data[0]!.ruta_json;
|
||||
|
||||
const line = polyline(coords, { color: props.color});
|
||||
line.addTo(g_map!);
|
||||
});
|
||||
|
||||
createEffect(() => {
|
||||
// Render the dots into the map
|
||||
const coords = return_points()!.data[0]!.ruta_json;
|
||||
|
||||
const line = polyline(coords, { color: props.color});
|
||||
line.addTo(g_map!);
|
||||
});
|
||||
|
||||
const departure_classes = () => {
|
||||
if (departure_count() > 0) {
|
||||
return "bg-r-hover-bg text-r-hover-on-bg";
|
||||
} else {
|
||||
return "";
|
||||
}
|
||||
};
|
||||
const return_classes = () => {
|
||||
if (return_count() > 0) {
|
||||
return "bg-r-hover-bg text-r-hover-on-bg";
|
||||
} else {
|
||||
return "";
|
||||
}
|
||||
};
|
||||
return (
|
||||
<button
|
||||
class="grid grid-cols-[auto_2.75rem_3.5rem] w-full text-left cursor-pointer"
|
||||
>
|
||||
<span
|
||||
class={"pl-10 border-2 border-transparent hover:border-r-hover-bg"}
|
||||
onMouseEnter={() => {
|
||||
set_global_count((c) => c + 1);
|
||||
set_departure_count((c) => c + 1);
|
||||
set_return_count((c) => c + 1);
|
||||
}}
|
||||
onMouseLeave={() => {
|
||||
set_global_count((c) => c - 1);
|
||||
set_departure_count((c) => c - 1);
|
||||
set_return_count((c) => c - 1);
|
||||
}}
|
||||
onClick={() => {
|
||||
if (departure_count() === 1) {
|
||||
toggle_departure();
|
||||
}
|
||||
if (return_count() === 1) {
|
||||
toggle_return();
|
||||
}
|
||||
}}
|
||||
>
|
||||
Ruta {props.route.name}
|
||||
</span>
|
||||
<span
|
||||
class={`text-center border-2 border-transparent ${departure_classes()}`}
|
||||
onMouseEnter={() => {
|
||||
set_global_count((c) => c + 1);
|
||||
set_departure_count((c) => c + 1);
|
||||
}}
|
||||
onMouseLeave={() => {
|
||||
set_global_count((c) => c - 1);
|
||||
set_departure_count((c) => c - 1);
|
||||
}}
|
||||
onClick={toggle_departure}
|
||||
>
|
||||
Ida
|
||||
</span>
|
||||
<span
|
||||
class={`text-center border-2 border-transparent ${return_classes()}`}
|
||||
onMouseEnter={() => {
|
||||
set_global_count((c) => c + 1);
|
||||
set_return_count((c) => c + 1);
|
||||
}}
|
||||
onMouseLeave={() => {
|
||||
set_global_count((c) => c - 1);
|
||||
set_return_count((c) => c - 1);
|
||||
}}
|
||||
onClick={toggle_return}
|
||||
>
|
||||
Vuelta
|
||||
</span>
|
||||
</button>
|
||||
<div class="pl-10">
|
||||
Ruta {props.route.cod_ruta}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -0,0 +1,221 @@
|
|||
import L from "leaflet";
|
||||
import { createEffect, createResource, createSignal, For, onMount, Suspense } from "solid-js";
|
||||
import { LineSegmentsIcon } from "../icons/LineSegmentsIcon";
|
||||
import { Line, Lines, Route, Routes } from "../new_types";
|
||||
|
||||
let global_map: L.Map | null = null;
|
||||
const [global_count, set_global_count] = createSignal(0);
|
||||
|
||||
export function Index2() {
|
||||
const container = <div class="md:h-[98vh] h-[65vh] md:rounded-lg dark:opacity-60" />;
|
||||
|
||||
onMount(() => {
|
||||
global_map = L.map(container as HTMLElement)
|
||||
.setView([-16.40171, -71.53040], 13);
|
||||
|
||||
L.tileLayer("/tiles/{z}/{x}/{y}.jpg", {
|
||||
maxZoom: 17,
|
||||
minZoom: 12,
|
||||
attribution: "Map data © <a href=\"http://www.openstreetmap.org/copyright\">OpenStreetMap</a>",
|
||||
}).addTo(global_map);
|
||||
});
|
||||
|
||||
return (
|
||||
<div class="grid md:grid-cols-[15rem_auto] md:grid-rows-none grid-rows-[65vh_35vh]">
|
||||
<div class="md:h-screen overflow-scroll">
|
||||
<h1 class="text-c-primary text-center font-bold text-2xl py-4">AQP combi</h1>
|
||||
|
||||
<h2 class="bg-c-primary text-white py-2 px-2 font-bold text-lg">
|
||||
Lineas
|
||||
</h2>
|
||||
|
||||
<LinesEl />
|
||||
</div>
|
||||
<div class="md:py-[0.5vh] md:pr-2">
|
||||
<div class="md:rounded-lg overflow-hidden md:p-1"
|
||||
style="box-shadow: inset 0 0 5px 0px var(--main)"
|
||||
>
|
||||
{container}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
function LinesEl() {
|
||||
const [linesData] = createResource<Lines>(async() => {
|
||||
const res = await fetch("/n/lines.json");
|
||||
if (!res.ok) throw new Error("Error fetching data");
|
||||
return res.json();
|
||||
});
|
||||
|
||||
return (
|
||||
<>
|
||||
<Suspense fallback={<div>Cargando...</div>}>
|
||||
<For each={linesData() ?? []}>
|
||||
{(l) => <LineEl line={l} />}
|
||||
</For>
|
||||
</Suspense>
|
||||
</>
|
||||
);
|
||||
}
|
||||
|
||||
function LineEl(props: { line: Line }) {
|
||||
const [routesData] = createResource<Routes>(async() => {
|
||||
const res = await fetch(`/n/routes_${props.line.id}.json`);
|
||||
if (!res.ok) throw new Error("Error fetching data");
|
||||
return res.json();
|
||||
});
|
||||
|
||||
return (
|
||||
<div
|
||||
style={`color: ${props.line.color};--hover-bg: ${props.line.hover_bg};--hover-on-bg: ${props.line.hover_on_bg}`}
|
||||
>
|
||||
<LineSegmentsIcon class="px-1" fill={props.line.color} />
|
||||
<span class="px-2" title={props.line.district}>
|
||||
Linea {props.line.name}
|
||||
</span>
|
||||
<Suspense>
|
||||
<For each={routesData() ?? []}>
|
||||
{(r) => (
|
||||
<RouteEl
|
||||
line_name={props.line.name}
|
||||
route={r}
|
||||
color={props.line.color}
|
||||
/>
|
||||
)}
|
||||
</For>
|
||||
</Suspense>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
function RouteEl(props: {
|
||||
line_name: string,
|
||||
route: Route,
|
||||
color: string,
|
||||
}) {
|
||||
const [departure_active, set_departure_active] = createSignal(false);
|
||||
const [return_active, set_return_active] = createSignal(false);
|
||||
const [departure_count, set_departure_count] = createSignal(0);
|
||||
const [return_count, set_return_count] = createSignal(0);
|
||||
|
||||
// Create departure and return polylines
|
||||
const departure_polyline = L.polyline(props.route.departure, { color: props.color });
|
||||
const return_polyline = L.polyline(props.route.return, { color: props.color });
|
||||
|
||||
// Rended the lines into the map
|
||||
createEffect(() => {
|
||||
if (global_count() === 0 || departure_count() > 0) {
|
||||
departure_polyline.addTo(global_map!);
|
||||
} else {
|
||||
departure_polyline.removeFrom(global_map!);
|
||||
}
|
||||
});
|
||||
createEffect(() => {
|
||||
// if global count === 0, then no route is focused.
|
||||
// in that case, all routes should be rendered
|
||||
if (global_count() === 0 || return_count() > 0) {
|
||||
return_polyline.addTo(global_map!);
|
||||
} else {
|
||||
return_polyline.removeFrom(global_map!);
|
||||
}
|
||||
});
|
||||
|
||||
const toggle_departure = () => {
|
||||
const currently_active = departure_active();
|
||||
if (currently_active) {
|
||||
set_global_count((c) => c - 1);
|
||||
set_departure_count((c) => c - 1);
|
||||
set_departure_active(false);
|
||||
} else {
|
||||
set_global_count((c) => c + 1);
|
||||
set_departure_count((c) => c + 1);
|
||||
set_departure_active(true);
|
||||
}
|
||||
};
|
||||
const toggle_return = () => {
|
||||
const currently_active = return_active();
|
||||
if (currently_active) {
|
||||
set_global_count((c) => c - 1);
|
||||
set_return_count((c) => c - 1);
|
||||
set_return_active(false);
|
||||
} else {
|
||||
set_global_count((c) => c + 1);
|
||||
set_return_count((c) => c + 1);
|
||||
set_return_active(true);
|
||||
}
|
||||
};
|
||||
|
||||
const departure_classes = () => {
|
||||
if (departure_count() > 0) {
|
||||
return "bg-r-hover-bg text-r-hover-on-bg";
|
||||
} else {
|
||||
return "";
|
||||
}
|
||||
};
|
||||
const return_classes = () => {
|
||||
if (return_count() > 0) {
|
||||
return "bg-r-hover-bg text-r-hover-on-bg";
|
||||
} else {
|
||||
return "";
|
||||
}
|
||||
};
|
||||
return (
|
||||
<button
|
||||
class="grid grid-cols-[auto_2.75rem_3.5rem] w-full text-left cursor-pointer"
|
||||
>
|
||||
<span
|
||||
class={"pl-10 border-2 border-transparent hover:border-r-hover-bg"}
|
||||
onMouseEnter={() => {
|
||||
set_global_count((c) => c + 1);
|
||||
set_departure_count((c) => c + 1);
|
||||
set_return_count((c) => c + 1);
|
||||
}}
|
||||
onMouseLeave={() => {
|
||||
set_global_count((c) => c - 1);
|
||||
set_departure_count((c) => c - 1);
|
||||
set_return_count((c) => c - 1);
|
||||
}}
|
||||
onClick={() => {
|
||||
if (departure_count() === 1) {
|
||||
toggle_departure();
|
||||
}
|
||||
if (return_count() === 1) {
|
||||
toggle_return();
|
||||
}
|
||||
}}
|
||||
>
|
||||
Ruta {props.route.name}
|
||||
</span>
|
||||
<span
|
||||
class={`text-center border-2 border-transparent ${departure_classes()}`}
|
||||
onMouseEnter={() => {
|
||||
set_global_count((c) => c + 1);
|
||||
set_departure_count((c) => c + 1);
|
||||
}}
|
||||
onMouseLeave={() => {
|
||||
set_global_count((c) => c - 1);
|
||||
set_departure_count((c) => c - 1);
|
||||
}}
|
||||
onClick={toggle_departure}
|
||||
>
|
||||
Ida
|
||||
</span>
|
||||
<span
|
||||
class={`text-center border-2 border-transparent ${return_classes()}`}
|
||||
onMouseEnter={() => {
|
||||
set_global_count((c) => c + 1);
|
||||
set_return_count((c) => c + 1);
|
||||
}}
|
||||
onMouseLeave={() => {
|
||||
set_global_count((c) => c - 1);
|
||||
set_return_count((c) => c - 1);
|
||||
}}
|
||||
onClick={toggle_return}
|
||||
>
|
||||
Vuelta
|
||||
</span>
|
||||
</button>
|
||||
);
|
||||
}
|
|
@ -1,154 +0,0 @@
|
|||
import { createEffect, createResource, createSignal, For, onMount } from "solid-js";
|
||||
import L from "leaflet";
|
||||
import { Line, Lines, Route, Routes } from "../new_types";
|
||||
|
||||
let global_map: L.Map | null = null;
|
||||
const [global_count, set_global_count] = createSignal(0);
|
||||
|
||||
export function IndexMobile() {
|
||||
const container = <div class="h-screen w-screen md:rounded-lg dark:opacity-80" />;
|
||||
|
||||
onMount(() => {
|
||||
// Detect screen size and ratio,
|
||||
// and redirect to pc page if neccesary
|
||||
if (!window.matchMedia("only screen and (max-width: 760px)").matches) {
|
||||
window.location.replace("/#/");
|
||||
return;
|
||||
}
|
||||
|
||||
global_map = L.map(container as HTMLElement)
|
||||
.setView([-16.40171, -71.53040], 13);
|
||||
|
||||
L.tileLayer("/tiles/{z}/{x}/{y}.jpg", {
|
||||
maxZoom: 17,
|
||||
minZoom: 12,
|
||||
attribution: "Map data © <a href=\"http://www.openstreetmap.org/copyright\">OpenStreetMap</a>",
|
||||
}).addTo(global_map);
|
||||
});
|
||||
|
||||
return (
|
||||
<div>
|
||||
{container}
|
||||
<LinesContainer />
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
function LinesContainer() {
|
||||
const [selected_line, set_selected_line] = createSignal(-1);
|
||||
const [linesData] = createResource<Lines>(async() => {
|
||||
const res = await fetch("/n/lines.json");
|
||||
if (!res.ok) throw new Error("Error fetching data");
|
||||
return res.json();
|
||||
});
|
||||
|
||||
return (
|
||||
<div class="fixed bottom-0 left-0 w-screen text-c-on-bg z-[500]">
|
||||
<div class="py-1">
|
||||
<For each={linesData() ?? []}>
|
||||
{(line) => <RouteChipContainer line={line} active_line={selected_line()} />}
|
||||
</For>
|
||||
</div>
|
||||
<div class="py-2 bg-c-bg">
|
||||
<For each={linesData() ?? []}>
|
||||
{(line) => (
|
||||
<LineChip
|
||||
line={line}
|
||||
activate={() => set_selected_line(line.id)}
|
||||
deactivate={() => set_selected_line(-1)}
|
||||
selected={selected_line() === line.id}
|
||||
/>
|
||||
)}
|
||||
</For>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
function LineChip(props: {
|
||||
line: Line,
|
||||
selected: boolean,
|
||||
activate: () => void,
|
||||
deactivate: () => void,
|
||||
}) {
|
||||
const active_classes = () => (props.selected ? "bg-r-hover-bg text-r-hover-on-bg" : "text-r-hover-bg");
|
||||
return (
|
||||
<button
|
||||
class={`inline-block border-2 border-r-hover-bg py-1 px-4 rounded-lg ml-2 font-bold ${active_classes()}`}
|
||||
style={`--hover-bg: ${props.line.hover_bg};--hover-on-bg: ${props.line.hover_on_bg}`}
|
||||
onClick={() => {
|
||||
if (props.selected) {
|
||||
props.deactivate();
|
||||
} else {
|
||||
props.activate();
|
||||
}
|
||||
}}
|
||||
>
|
||||
Linea {props.line.name}
|
||||
</button>
|
||||
);
|
||||
}
|
||||
|
||||
function RouteChipContainer(props: {line: Line, active_line: number}) {
|
||||
const [routesData] = createResource<Routes>(async() => {
|
||||
const res = await fetch(`/n/routes_${props.line.id}.json`);
|
||||
if (!res.ok) throw new Error("Error fetching data");
|
||||
return res.json();
|
||||
});
|
||||
|
||||
const container_classes = () => (props.active_line === props.line.id ? "inline-block" : "hidden");
|
||||
return (
|
||||
<div class={container_classes()}
|
||||
style={`--hover-bg: ${props.line.hover_bg};--hover-on-bg: ${props.line.hover_on_bg}`}
|
||||
>
|
||||
<For each={routesData() ?? []}>
|
||||
{(route) => <RouteChip route={route} color={props.line.color} />}
|
||||
</For>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
function RouteChip(props: {route: Route, color: string}) {
|
||||
const route = props.route;
|
||||
const [active, set_active] = createSignal(false);
|
||||
|
||||
// Create departure and return polylines
|
||||
const departure_polyline = L.polyline(route.departure, { color: props.color });
|
||||
const return_polyline = L.polyline(route.return, { color: props.color });
|
||||
|
||||
// Render the lines into the map
|
||||
// TODO: Change the UI to allow selecting departure and return separately
|
||||
// and then update this
|
||||
|
||||
createEffect(() => {
|
||||
if (global_count() === 0 || active() === true) {
|
||||
departure_polyline.addTo(global_map!);
|
||||
return_polyline.addTo(global_map!);
|
||||
} else {
|
||||
departure_polyline.removeFrom(global_map!);
|
||||
return_polyline.removeFrom(global_map!);
|
||||
}
|
||||
});
|
||||
|
||||
const toggle_active = () => {
|
||||
if (active()) {
|
||||
set_active(false);
|
||||
set_global_count((c) => c - 1);
|
||||
} else {
|
||||
set_active(true);
|
||||
set_global_count((c) => c + 1);
|
||||
}
|
||||
};
|
||||
|
||||
const active_classes = () => (active() === true ? "bg-r-hover-bg text-r-hover-on-bg" : "bg-white text-r-hover-bg");
|
||||
return (
|
||||
<button
|
||||
class={`inline-block rounded-full ml-2 border border-r-hover-bg py-1 px-2
|
||||
${active_classes()}`}
|
||||
onClick={toggle_active}
|
||||
>
|
||||
Ruta {route.name}
|
||||
</button>
|
||||
);
|
||||
}
|
||||
|
Loading…
Reference in New Issue