Move mobile UI to its own page, and redirect to it

master
Araozu 2024-09-09 16:34:01 -05:00
parent b836e5e8eb
commit 1672d4de94
3 changed files with 156 additions and 1 deletions

View File

@ -3,12 +3,14 @@ import { Route, HashRouter } from "@solidjs/router";
import { Editor } from "./pages/Editor";
import { Index } from "./pages/Index";
import { Arrow } from "./pages/Arrow";
import { IndexMobile } from "./pages/IndexMobile";
export default function() {
return (
<>
<HashRouter>
<Route path="/" component={Index} />
<Route path="/mobile" component={IndexMobile} />
<Route path="/editor" component={Editor} />
<Route path="/arrow" component={Arrow} />
</HashRouter>

View File

@ -10,6 +10,13 @@ export function Index() {
const container = <div class="md:h-[98vh] h-[65vh] md: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)
.setView([-16.40171, -71.53040], 13);

View File

@ -1,8 +1,154 @@
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 &copy; <a href=\"http://www.openstreetmap.org/copyright\">OpenStreetMap</a>",
}).addTo(global_map);
});
return (
<div>
Mobile index :D
{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>
);
}