Skip to content

Commit

Permalink
Use shadow realm Web APIs to sync Themes beteen tabs
Browse files Browse the repository at this point in the history
  • Loading branch information
Comeza committed Jun 13, 2024
1 parent 5cb402d commit 11f6a67
Show file tree
Hide file tree
Showing 8 changed files with 82 additions and 70 deletions.
15 changes: 1 addition & 14 deletions liberica/src/components/Navbar.tsx
Original file line number Diff line number Diff line change
@@ -1,22 +1,9 @@
import { PropsWithChildren } from "react";
import { FaHome } from "react-icons/fa";
import { useNavigate } from "react-router-dom";
import { Button } from "components/lila/button";

export function Navbar(props: PropsWithChildren) {
return (
<div className="fixed bottom-0 z-auto flex w-dvw items-center justify-between gap-3 bg-base p-2">
<div className="fixed bottom-0 z-auto flex max-h-14 w-dvw items-center justify-between gap-3 rounded-t-2xl bg-base p-2">
{props.children}
</div>
);
}

export function HomeButton() {
const navigate = useNavigate();

return (
<Button onClick={() => navigate("/")} variant="primary" size="lg">
<FaHome />
</Button>
);
}
26 changes: 3 additions & 23 deletions liberica/src/components/map/Map.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,6 @@ import {
import { createContext, useContext, useEffect, useState } from "react";
import { useTranslation } from "react-i18next";
import { MrXIcon, TrainIcon, DetectiveIcon } from "components/MapIcons";
import { Button } from "components/lila";
import { Marker } from "./Marker";
import { GameState, Stop, TeamState, Train } from "lib/bindings";
import { getStops } from "lib/api";
Expand All @@ -28,29 +27,10 @@ const CENTER: [number, number] = [49.0046, 8.403];
const DEFAULT_ZOOM = 15;

export type MapProps = React.PropsWithChildren<{
tileProps?: Partial<TileLayerProps>;
containerProps?: Partial<MapContainerProps>;
tileProps?: Omit<Partial<TileLayerProps>, "className">;
containerProps?: Omit<Partial<MapContainerProps>, "className">;
}>;

function ResetMapViewButton() {
const map = useMap();
const { t } = useTranslation();

return (
<div className="leaflet-top leaflet-center">
<div className="leaflet-control leaflet-bar">
<Button
onClick={() => map.setView(CENTER, DEFAULT_ZOOM)}
variant={"primary"}
size="lg"
>
{t("ResetMapView")}
</Button>
</div>
</div>
);
}

function TrainMarker(props: {
train: Train;
onClick?: (train: Train) => void;
Expand Down Expand Up @@ -177,7 +157,7 @@ export function Map(
</LayerGroup>
</LayersControl.Overlay>
</LayersControl>
<ResetMapViewButton />

{props.children}
</MapContainer>
);
Expand Down
3 changes: 2 additions & 1 deletion liberica/src/i18n/de.json
Original file line number Diff line number Diff line change
Expand Up @@ -18,5 +18,6 @@
"FailedParseReplay": "Replay-Datei konnte nicht geparst werden",
"ReplayTooBig": "Replay-Datei ist zu groß",
"Speed": "Geschwindigkeit",
"Cancel": "Abbrechen"
"Cancel": "Abbrechen",
"EmbarkPlaceholder": "Zum einsteigen auf Zug klicken"
}
3 changes: 2 additions & 1 deletion liberica/src/i18n/en.json
Original file line number Diff line number Diff line change
Expand Up @@ -18,5 +18,6 @@
"FailedParseReplay": "failed to parse replay file",
"ReplayTooBig": "replay file is too big",
"Speed": "Speed",
"Cancel": "Cancel"
"Cancel": "Cancel",
"EmbarkPlaceholder": "Click on train to embark"
}
34 changes: 31 additions & 3 deletions liberica/src/lib/theme.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,10 +2,25 @@ import THEMES_JSON from "assets/themes.json";
import { hexToHSL } from "lib/colors";
import { camelToKebabCase } from "lib/util";

const LOCAL_STORAGE_THEME_KEY = "theme";
const BROADCAST_CHANNEL_NAME = "theme";

export type ThemeName = keyof typeof THEMES_JSON;

export const THEMES: Record<ThemeName, Theme> = THEMES_JSON;
export const THEME_NAMES = Object.keys(THEMES) as ThemeName[];

export const BROADCAST_CHANNEL = new BroadcastChannel(BROADCAST_CHANNEL_NAME);

BROADCAST_CHANNEL.onmessage = (msg: { data: ThemeName }) => {
console.debug(
`Received Boradcast Message on channel ${BROADCAST_CHANNEL_NAME}: `,
msg.data,
);
if (!THEME_NAMES.includes(msg.data)) return;
applyTheme(msg.data, { persistent: false, broadcast: false });
};

export interface Theme {
base: string;
surface: string;
Expand All @@ -20,8 +35,6 @@ export interface Theme {
onMuted: string;
}

const LOCAL_STORAGE_THEME_KEY = "theme";

export function saveTheme(themeName?: ThemeName) {
if (!themeName) {
localStorage.removeItem(LOCAL_STORAGE_THEME_KEY);
Expand All @@ -35,8 +48,22 @@ export function loadTheme(): ThemeName | null {
return localStorage.getItem(LOCAL_STORAGE_THEME_KEY) as ThemeName | null;
}

export function applyTheme(themeName: ThemeName, persistent = false) {
export interface ApplyThemeOptions {
persistent: boolean;
broadcast: boolean;
}

const applyThemeOptionsDefaults: ApplyThemeOptions = {
persistent: false,
broadcast: false,
};

export function applyTheme(themeName: ThemeName, options: ApplyThemeOptions) {
console.assert(THEME_NAMES.includes(themeName), "Set Theme does not exist");
const { persistent, broadcast } = {
...applyThemeOptionsDefaults,
...options,
};

const style = document.documentElement.style;
const theme = THEMES[themeName];
Expand All @@ -58,4 +85,5 @@ export function applyTheme(themeName: ThemeName, persistent = false) {
}

if (persistent) saveTheme(themeName);
if (broadcast) BROADCAST_CHANNEL.postMessage(themeName);
}
7 changes: 6 additions & 1 deletion liberica/src/page/Debug.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,12 @@ export function Debug() {
></TextInput>

<select
onChange={(e) => applyTheme(e.target.value as ThemeName, true)}
onChange={(e) =>
applyTheme(e.target.value as ThemeName, {
broadcast: true,
persistent: true,
})
}
>
{Object.keys(THEMES).map((theme) => (
<option key={theme}>{theme}</option>
Expand Down
60 changes: 36 additions & 24 deletions liberica/src/page/Game.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ import { GameState, Team, Train } from "lib/bindings";
import { WebSocketApi } from "lib/websockets";
import { useEffect, useState } from "react";
import { useLocation } from "react-router-dom";
import { HomeButton, Navbar } from "components/Navbar";
import { Navbar } from "components/Navbar";
import { Button } from "components/lila/button";
import { useTranslation } from "react-i18next";

Expand Down Expand Up @@ -66,12 +66,26 @@ export function Game() {
}
}, [ws]);

const widgetEmbarkedTrain = (
<div className="flex h-full w-full flex-col truncate rounded-xl rounded-xl bg-muted/10 px-4 py-2.5 text-sm text-on-muted">
{embarkedTrain ? (
<span className="truncate">
{embarkedTrain.line_name} {embarkedTrain.direction}
</span>
) : (
<span className="truncate italic text-on-muted/50">
{t("EmbarkPlaceholder")}
</span>
)}
</div>
);

const Game = (
<div className="flex h-dvh w-dvw flex-col">
<GameStateContext.Provider value={gs}>
<Map
tileProps={{ updateInterval: 500 }}
containerProps={{ preferCanvas: true }}
containerProps={{ preferCanvas: true, zoomControl: false }}
onStopClick={(stop) => {
if (team) {
disembark();
Expand All @@ -85,30 +99,30 @@ export function Game() {
}}
onTrainClick={embark}
/>
</GameStateContext.Provider>

<Navbar>
<HomeButton />

{embarkedTrain && (
<span>
{embarkedTrain.line_name} {embarkedTrain.direction}
</span>
)}

<Button
disabled={!embarkedTrain}
onClick={disembark}
variant={"primary"}
size="lg"
>
{t("Disembark")}
</Button>
</Navbar>
<Navbar>
{widgetEmbarkedTrain}

<Button
disabled={!embarkedTrain}
onClick={disembark}
variant={"primary"}
size="lg"
>
{t("Disembark")}
</Button>
</Navbar>
</GameStateContext.Provider>
</div>
);

const LandingPage = (
return ws ? Game : <LandingPage />;
}

function LandingPage() {
const { t } = useTranslation();

return (
<div className="flex h-dvh w-dvw flex-col items-center justify-center gap-5">
<div className="flex flex-col items-center">
<span className="italic text-on-base">
Expand All @@ -118,6 +132,4 @@ export function Game() {
</div>
</div>
);

return ws ? Game : LandingPage;
}
4 changes: 1 addition & 3 deletions liberica/src/page/Replay.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ import { useRef, useState } from "react";
import { useInterval } from "use-interval";
import { GameStateContext, Map } from "components/map/Map";
import { Button } from "components/lila";
import { HomeButton, Navbar } from "components/Navbar";
import { Navbar } from "components/Navbar";
import { GameState } from "lib/bindings";
import { clamp } from "lib/util";
import schema from "lib/schema";
Expand Down Expand Up @@ -173,8 +173,6 @@ export function Replay() {
</GameStateContext.Provider>

<Navbar>
<HomeButton />

<input
type="file"
onChange={(e) => {
Expand Down

0 comments on commit 11f6a67

Please sign in to comment.