Typescript
This commit is contained in:
parent
2a053f4854
commit
a4363e542c
|
@ -99,6 +99,7 @@
|
||||||
"@types/deep-diff": "^1.0.0",
|
"@types/deep-diff": "^1.0.0",
|
||||||
"@types/file-saver": "^2.0.2",
|
"@types/file-saver": "^2.0.2",
|
||||||
"@types/jest": "^26.0.23",
|
"@types/jest": "^26.0.23",
|
||||||
|
"@types/lodash.chunk": "^4.2.6",
|
||||||
"@types/lodash.clonedeep": "^4.5.6",
|
"@types/lodash.clonedeep": "^4.5.6",
|
||||||
"@types/lodash.get": "^4.4.6",
|
"@types/lodash.get": "^4.4.6",
|
||||||
"@types/lodash.set": "^4.3.6",
|
"@types/lodash.set": "^4.3.6",
|
||||||
|
|
|
@ -18,11 +18,13 @@ import SelectDiceButton from "./SelectDiceButton";
|
||||||
|
|
||||||
import Divider from "../Divider";
|
import Divider from "../Divider";
|
||||||
|
|
||||||
|
import Dice from "../../dice/Dice";
|
||||||
|
|
||||||
import { dice } from "../../dice";
|
import { dice } from "../../dice";
|
||||||
import useSetting from "../../hooks/useSetting";
|
import useSetting from "../../hooks/useSetting";
|
||||||
|
|
||||||
import { DefaultDice, DiceRoll, DiceType } from "../../types/Dice";
|
import { DefaultDice, DiceRoll, DiceType } from "../../types/Dice";
|
||||||
import Dice from "../../dice/Dice";
|
import { DiceShareChangeEventHandler } from "../../types/Events";
|
||||||
|
|
||||||
type DiceButtonsProps = {
|
type DiceButtonsProps = {
|
||||||
diceRolls: DiceRoll[];
|
diceRolls: DiceRoll[];
|
||||||
|
@ -31,7 +33,7 @@ type DiceButtonsProps = {
|
||||||
diceTraySize: "single" | "double";
|
diceTraySize: "single" | "double";
|
||||||
onDiceTraySizeChange: (newSize: "single" | "double") => void;
|
onDiceTraySizeChange: (newSize: "single" | "double") => void;
|
||||||
shareDice: boolean;
|
shareDice: boolean;
|
||||||
onShareDiceChange: (value: boolean) => void;
|
onShareDiceChange: DiceShareChangeEventHandler;
|
||||||
loading: boolean;
|
loading: boolean;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -3,6 +3,7 @@ import { Vector3 } from "@babylonjs/core/Maths/math";
|
||||||
import { DirectionalLight } from "@babylonjs/core/Lights/directionalLight";
|
import { DirectionalLight } from "@babylonjs/core/Lights/directionalLight";
|
||||||
import { ShadowGenerator } from "@babylonjs/core/Lights/Shadows/shadowGenerator";
|
import { ShadowGenerator } from "@babylonjs/core/Lights/Shadows/shadowGenerator";
|
||||||
import { CubeTexture } from "@babylonjs/core/Materials/Textures/cubeTexture";
|
import { CubeTexture } from "@babylonjs/core/Materials/Textures/cubeTexture";
|
||||||
|
import { Scene } from "@babylonjs/core";
|
||||||
import { Box } from "theme-ui";
|
import { Box } from "theme-ui";
|
||||||
|
|
||||||
// @ts-ignore
|
// @ts-ignore
|
||||||
|
@ -19,16 +20,21 @@ import DiceTray from "../../dice/diceTray/DiceTray";
|
||||||
import { useDiceLoading } from "../../contexts/DiceLoadingContext";
|
import { useDiceLoading } from "../../contexts/DiceLoadingContext";
|
||||||
|
|
||||||
import { getDiceRoll } from "../../helpers/dice";
|
import { getDiceRoll } from "../../helpers/dice";
|
||||||
|
|
||||||
import useSetting from "../../hooks/useSetting";
|
import useSetting from "../../hooks/useSetting";
|
||||||
|
|
||||||
import { DefaultDice, DiceMesh, DiceRoll, DiceType } from "../../types/Dice";
|
import { DefaultDice, DiceMesh, DiceRoll, DiceType } from "../../types/Dice";
|
||||||
import { Scene } from "@babylonjs/core";
|
import {
|
||||||
|
DiceRollsChangeEventHandler,
|
||||||
|
DiceShareChangeEventHandler,
|
||||||
|
} from "../../types/Events";
|
||||||
|
|
||||||
type DiceTrayOverlayProps = {
|
type DiceTrayOverlayProps = {
|
||||||
isOpen: boolean;
|
isOpen: boolean;
|
||||||
shareDice: boolean;
|
shareDice: boolean;
|
||||||
onShareDiceChange: () => void;
|
onShareDiceChange: DiceShareChangeEventHandler;
|
||||||
diceRolls: DiceRoll[];
|
diceRolls: DiceRoll[];
|
||||||
onDiceRollsChange: (newRolls: DiceRoll[]) => void;
|
onDiceRollsChange: DiceRollsChangeEventHandler;
|
||||||
};
|
};
|
||||||
|
|
||||||
function DiceTrayOverlay({
|
function DiceTrayOverlay({
|
||||||
|
|
|
@ -12,7 +12,6 @@ import MapMeasure from "./MapMeasure";
|
||||||
import NetworkedMapPointer from "../../network/NetworkedMapPointer";
|
import NetworkedMapPointer from "../../network/NetworkedMapPointer";
|
||||||
import MapNotes from "./MapNotes";
|
import MapNotes from "./MapNotes";
|
||||||
|
|
||||||
import { useTokenData } from "../../contexts/TokenDataContext";
|
|
||||||
import { useSettings } from "../../contexts/SettingsContext";
|
import { useSettings } from "../../contexts/SettingsContext";
|
||||||
|
|
||||||
import TokenMenu from "../token/TokenMenu";
|
import TokenMenu from "../token/TokenMenu";
|
||||||
|
@ -29,13 +28,12 @@ import {
|
||||||
import Session from "../../network/Session";
|
import Session from "../../network/Session";
|
||||||
import { Drawing, DrawingState } from "../../types/Drawing";
|
import { Drawing, DrawingState } from "../../types/Drawing";
|
||||||
import { Fog, FogState } from "../../types/Fog";
|
import { Fog, FogState } from "../../types/Fog";
|
||||||
import { Map, MapActions, MapToolId } from "../../types/Map";
|
import { Map as MapType, MapActions, MapToolId } from "../../types/Map";
|
||||||
import { MapState } from "../../types/MapState";
|
import { MapState } from "../../types/MapState";
|
||||||
import { Settings } from "../../types/Settings";
|
import { Settings } from "../../types/Settings";
|
||||||
import {
|
import {
|
||||||
MapChangeEventHandler,
|
MapChangeEventHandler,
|
||||||
MapResetEventHandler,
|
MapResetEventHandler,
|
||||||
MapTokensStateCreateHandler,
|
|
||||||
MapTokenStateRemoveHandler,
|
MapTokenStateRemoveHandler,
|
||||||
NoteChangeEventHandler,
|
NoteChangeEventHandler,
|
||||||
NoteRemoveEventHander,
|
NoteRemoveEventHander,
|
||||||
|
@ -47,7 +45,7 @@ import { TokenDraggingOptions, TokenMenuOptions } from "../../types/Token";
|
||||||
import { Note, NoteDraggingOptions, NoteMenuOptions } from "../../types/Note";
|
import { Note, NoteDraggingOptions, NoteMenuOptions } from "../../types/Note";
|
||||||
|
|
||||||
type MapProps = {
|
type MapProps = {
|
||||||
map: Map | null;
|
map: MapType | null;
|
||||||
mapState: MapState | null;
|
mapState: MapState | null;
|
||||||
mapActions: MapActions;
|
mapActions: MapActions;
|
||||||
onMapTokenStateChange: TokenStateChangeEventHandler;
|
onMapTokenStateChange: TokenStateChangeEventHandler;
|
||||||
|
@ -95,8 +93,6 @@ function Map({
|
||||||
}: MapProps) {
|
}: MapProps) {
|
||||||
const { addToast } = useToasts();
|
const { addToast } = useToasts();
|
||||||
|
|
||||||
const { tokensById } = useTokenData();
|
|
||||||
|
|
||||||
const [selectedToolId, setSelectedToolId] = useState<MapToolId>("move");
|
const [selectedToolId, setSelectedToolId] = useState<MapToolId>("move");
|
||||||
const { settings, setSettings } = useSettings();
|
const { settings, setSettings } = useSettings();
|
||||||
|
|
||||||
|
|
|
@ -193,7 +193,11 @@ function MapInteraction({
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<MapInteractionProvider value={mapInteraction}>
|
<MapInteractionProvider value={mapInteraction}>
|
||||||
<GridProvider grid={map?.grid} width={mapWidth} height={mapHeight}>
|
<GridProvider
|
||||||
|
grid={map?.grid || null}
|
||||||
|
width={mapWidth}
|
||||||
|
height={mapHeight}
|
||||||
|
>
|
||||||
<Box
|
<Box
|
||||||
sx={{
|
sx={{
|
||||||
position: "relative",
|
position: "relative",
|
||||||
|
|
|
@ -52,7 +52,7 @@ function MapMeasure({ map, active }: MapMeasureProps) {
|
||||||
useState<MeasureData | null>(null);
|
useState<MeasureData | null>(null);
|
||||||
const [isBrushDown, setIsBrushDown] = useState(false);
|
const [isBrushDown, setIsBrushDown] = useState(false);
|
||||||
|
|
||||||
const gridScale = parseGridScale(active && grid.measurement.scale);
|
const gridScale = parseGridScale(active ? grid.measurement.scale : null);
|
||||||
|
|
||||||
const snapPositionToGrid = useGridSnapping(
|
const snapPositionToGrid = useGridSnapping(
|
||||||
grid.measurement.type === "euclidean" ? 0 : 1,
|
grid.measurement.type === "euclidean" ? 0 : 1,
|
||||||
|
|
|
@ -1,4 +1,3 @@
|
||||||
import React from "react";
|
|
||||||
import { Grid } from "theme-ui";
|
import { Grid } from "theme-ui";
|
||||||
|
|
||||||
import Tile from "../tile/Tile";
|
import Tile from "../tile/Tile";
|
||||||
|
|
|
@ -9,15 +9,14 @@ type MapTileImageProps = {
|
||||||
} & ImageProps;
|
} & ImageProps;
|
||||||
|
|
||||||
function MapTileImage({ map, ...props }: MapTileImageProps) {
|
function MapTileImage({ map, ...props }: MapTileImageProps) {
|
||||||
const mapURL = useDataURL(
|
const mapURL = useDataURL(
|
||||||
map,
|
map,
|
||||||
defaultMapSources,
|
defaultMapSources,
|
||||||
undefined,
|
undefined,
|
||||||
map.type === "file"
|
map.type === "file"
|
||||||
);
|
);
|
||||||
|
|
||||||
return <Image src={mapURL} {...props} />;
|
return <Image src={mapURL} {...props} />;
|
||||||
}
|
}
|
||||||
);
|
|
||||||
|
|
||||||
export default MapTileImage;
|
export default MapTileImage;
|
||||||
|
|
|
@ -26,11 +26,14 @@ import { useKeyboard } from "../../../contexts/KeyboardContext";
|
||||||
|
|
||||||
import shortcuts from "../../../shortcuts";
|
import shortcuts from "../../../shortcuts";
|
||||||
|
|
||||||
import { DrawingToolSettings, DrawingToolType } from "../../../types/Drawing";
|
import {
|
||||||
|
DrawingToolSettings as DrawingToolSettingsType,
|
||||||
|
DrawingToolType,
|
||||||
|
} from "../../../types/Drawing";
|
||||||
|
|
||||||
type DrawingToolSettingsProps = {
|
type DrawingToolSettingsProps = {
|
||||||
settings: DrawingToolSettings;
|
settings: DrawingToolSettingsType;
|
||||||
onSettingChange: (change: Partial<DrawingToolSettings>) => void;
|
onSettingChange: (change: Partial<DrawingToolSettingsType>) => void;
|
||||||
onToolAction: (action: string) => void;
|
onToolAction: (action: string) => void;
|
||||||
disabledActions: string[];
|
disabledActions: string[];
|
||||||
};
|
};
|
||||||
|
|
|
@ -23,11 +23,14 @@ import { useKeyboard } from "../../../contexts/KeyboardContext";
|
||||||
|
|
||||||
import shortcuts from "../../../shortcuts";
|
import shortcuts from "../../../shortcuts";
|
||||||
|
|
||||||
import { FogToolSettings, FogToolType } from "../../../types/Fog";
|
import {
|
||||||
|
FogToolSettings as FogToolSettingsType,
|
||||||
|
FogToolType,
|
||||||
|
} from "../../../types/Fog";
|
||||||
|
|
||||||
type FogToolSettingsProps = {
|
type FogToolSettingsProps = {
|
||||||
settings: FogToolSettings;
|
settings: FogToolSettingsType;
|
||||||
onSettingChange: (change: Partial<FogToolSettings>) => void;
|
onSettingChange: (change: Partial<FogToolSettingsType>) => void;
|
||||||
onToolAction: (action: string) => void;
|
onToolAction: (action: string) => void;
|
||||||
disabledActions: string[];
|
disabledActions: string[];
|
||||||
};
|
};
|
||||||
|
|
|
@ -2,11 +2,11 @@ import { Flex } from "theme-ui";
|
||||||
|
|
||||||
import ColorControl from "./ColorControl";
|
import ColorControl from "./ColorControl";
|
||||||
|
|
||||||
import { PointerToolSettings } from "../../../types/Pointer";
|
import { PointerToolSettings as PointerToolSettingsType } from "../../../types/Pointer";
|
||||||
|
|
||||||
type PointerToolSettingsProps = {
|
type PointerToolSettingsProps = {
|
||||||
settings: PointerToolSettings;
|
settings: PointerToolSettingsType;
|
||||||
onSettingChange: (change: Partial<PointerToolSettings>) => void;
|
onSettingChange: (change: Partial<PointerToolSettingsType>) => void;
|
||||||
};
|
};
|
||||||
|
|
||||||
function PointerToolSettings({
|
function PointerToolSettings({
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
import React, { useState } from "react";
|
import { useState } from "react";
|
||||||
import { IconButton } from "theme-ui";
|
import { IconButton } from "theme-ui";
|
||||||
|
|
||||||
import AddPartyMemberModal from "../../modals/AddPartyMemberModal";
|
import AddPartyMemberModal from "../../modals/AddPartyMemberModal";
|
||||||
|
|
|
@ -1,16 +1,18 @@
|
||||||
import React, { useState, useEffect, ChangeEvent } from "react";
|
import { useState, useEffect, ChangeEvent, FormEvent } from "react";
|
||||||
import { IconButton } from "theme-ui";
|
import { IconButton } from "theme-ui";
|
||||||
|
|
||||||
import ChangeNicknameModal from "../../modals/ChangeNicknameModal";
|
import ChangeNicknameModal from "../../modals/ChangeNicknameModal";
|
||||||
import ChangeNicknameIcon from "../../icons/ChangeNicknameIcon";
|
import ChangeNicknameIcon from "../../icons/ChangeNicknameIcon";
|
||||||
|
|
||||||
|
type ChangeNicknameButtonProps = {
|
||||||
|
nickname: string;
|
||||||
|
onChange: (nickname: string) => void;
|
||||||
|
};
|
||||||
|
|
||||||
function ChangeNicknameButton({
|
function ChangeNicknameButton({
|
||||||
nickname,
|
nickname,
|
||||||
onChange,
|
onChange,
|
||||||
}: {
|
}: ChangeNicknameButtonProps) {
|
||||||
nickname: string;
|
|
||||||
onChange;
|
|
||||||
}) {
|
|
||||||
const [isChangeModalOpen, setIsChangeModalOpen] = useState(false);
|
const [isChangeModalOpen, setIsChangeModalOpen] = useState(false);
|
||||||
function openModal() {
|
function openModal() {
|
||||||
setIsChangeModalOpen(true);
|
setIsChangeModalOpen(true);
|
||||||
|
@ -25,7 +27,7 @@ function ChangeNicknameButton({
|
||||||
setChangedNickname(nickname);
|
setChangedNickname(nickname);
|
||||||
}, [nickname]);
|
}, [nickname]);
|
||||||
|
|
||||||
function handleChangeSubmit(event: Event) {
|
function handleChangeSubmit(event: FormEvent) {
|
||||||
event.preventDefault();
|
event.preventDefault();
|
||||||
onChange(changedNickname);
|
onChange(changedNickname);
|
||||||
closeModal();
|
closeModal();
|
||||||
|
|
|
@ -1,14 +1,13 @@
|
||||||
import { Flex, Box, Text } from "theme-ui";
|
import { Flex, Box, Text } from "theme-ui";
|
||||||
|
import { DiceRoll as DiceRollType, DiceType } from "../../types/Dice";
|
||||||
|
|
||||||
function DiceRoll({
|
type DiceRollProps = {
|
||||||
rolls,
|
rolls: DiceRollType[];
|
||||||
type,
|
type: DiceType;
|
||||||
children,
|
children: React.ReactNode;
|
||||||
}: {
|
};
|
||||||
rolls;
|
|
||||||
type: string;
|
function DiceRoll({ rolls, type, children }: DiceRollProps) {
|
||||||
children;
|
|
||||||
}) {
|
|
||||||
return (
|
return (
|
||||||
<Flex sx={{ flexWrap: "wrap" }}>
|
<Flex sx={{ flexWrap: "wrap" }}>
|
||||||
<Box sx={{ transform: "scale(0.8)" }}>{children}</Box>
|
<Box sx={{ transform: "scale(0.8)" }}>{children}</Box>
|
||||||
|
|
|
@ -13,8 +13,9 @@ import D100Icon from "../../icons/D100Icon";
|
||||||
import DiceRoll from "./DiceRoll";
|
import DiceRoll from "./DiceRoll";
|
||||||
|
|
||||||
import { getDiceRollTotal } from "../../helpers/dice";
|
import { getDiceRollTotal } from "../../helpers/dice";
|
||||||
|
import { DiceRoll as DiceRollType, DiceType } from "../../types/Dice";
|
||||||
|
|
||||||
const diceIcons = [
|
const diceIcons: { type: DiceType; Icon: React.ElementType }[] = [
|
||||||
{ type: "d20", Icon: D20Icon },
|
{ type: "d20", Icon: D20Icon },
|
||||||
{ type: "d12", Icon: D12Icon },
|
{ type: "d12", Icon: D12Icon },
|
||||||
{ type: "d10", Icon: D10Icon },
|
{ type: "d10", Icon: D10Icon },
|
||||||
|
@ -24,7 +25,11 @@ const diceIcons = [
|
||||||
{ type: "d100", Icon: D100Icon },
|
{ type: "d100", Icon: D100Icon },
|
||||||
];
|
];
|
||||||
|
|
||||||
function DiceRolls({ rolls }: { rolls }) {
|
type DiceRollsProps = {
|
||||||
|
rolls: DiceRollType[];
|
||||||
|
};
|
||||||
|
|
||||||
|
function DiceRolls({ rolls }: DiceRollsProps) {
|
||||||
const total = getDiceRollTotal(rolls);
|
const total = getDiceRollTotal(rolls);
|
||||||
|
|
||||||
const [expanded, setExpanded] = useState<boolean>(false);
|
const [expanded, setExpanded] = useState<boolean>(false);
|
||||||
|
|
|
@ -9,19 +9,27 @@ import useSetting from "../../hooks/useSetting";
|
||||||
|
|
||||||
import LoadingOverlay from "../LoadingOverlay";
|
import LoadingOverlay from "../LoadingOverlay";
|
||||||
|
|
||||||
|
import {
|
||||||
|
DiceShareChangeEventHandler,
|
||||||
|
DiceRollsChangeEventHandler,
|
||||||
|
} from "../../types/Events";
|
||||||
|
import { DiceRoll } from "../../types/Dice";
|
||||||
|
|
||||||
const DiceTrayOverlay = React.lazy(() => import("../dice/DiceTrayOverlay"));
|
const DiceTrayOverlay = React.lazy(() => import("../dice/DiceTrayOverlay"));
|
||||||
|
|
||||||
|
type DiceTrayButtonProps = {
|
||||||
|
shareDice: boolean;
|
||||||
|
onShareDiceChange: DiceShareChangeEventHandler;
|
||||||
|
diceRolls: DiceRoll[];
|
||||||
|
onDiceRollsChange: DiceRollsChangeEventHandler;
|
||||||
|
};
|
||||||
|
|
||||||
function DiceTrayButton({
|
function DiceTrayButton({
|
||||||
shareDice,
|
shareDice,
|
||||||
onShareDiceChange,
|
onShareDiceChange,
|
||||||
diceRolls,
|
diceRolls,
|
||||||
onDiceRollsChange,
|
onDiceRollsChange,
|
||||||
}: {
|
}: DiceTrayButtonProps) {
|
||||||
shareDice: boolean;
|
|
||||||
onShareDiceChange;
|
|
||||||
diceRolls: [];
|
|
||||||
onDiceRollsChange;
|
|
||||||
}) {
|
|
||||||
const [isExpanded, setIsExpanded] = useState(false);
|
const [isExpanded, setIsExpanded] = useState(false);
|
||||||
const [fullScreen] = useSetting("map.fullScreen");
|
const [fullScreen] = useSetting("map.fullScreen");
|
||||||
|
|
||||||
|
|
|
@ -2,17 +2,15 @@ import { Text, Flex } from "theme-ui";
|
||||||
|
|
||||||
import Stream from "./Stream";
|
import Stream from "./Stream";
|
||||||
import DiceRolls from "./DiceRolls";
|
import DiceRolls from "./DiceRolls";
|
||||||
|
import { DiceRoll } from "../../types/Dice";
|
||||||
|
|
||||||
// TODO: check if stream is a required or optional param
|
type NicknameProps = {
|
||||||
function Nickname({
|
|
||||||
nickname,
|
|
||||||
stream,
|
|
||||||
diceRolls,
|
|
||||||
}: {
|
|
||||||
nickname: string;
|
nickname: string;
|
||||||
stream?;
|
stream?: MediaStream;
|
||||||
diceRolls;
|
diceRolls?: DiceRoll[];
|
||||||
}) {
|
};
|
||||||
|
|
||||||
|
function Nickname({ nickname, stream, diceRolls }: NicknameProps) {
|
||||||
return (
|
return (
|
||||||
<Flex sx={{ flexDirection: "column" }}>
|
<Flex sx={{ flexDirection: "column" }}>
|
||||||
<Text
|
<Text
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
import React, { useEffect } from "react";
|
import { useEffect } from "react";
|
||||||
import { Flex, Box, Text } from "theme-ui";
|
import { Flex, Box, Text } from "theme-ui";
|
||||||
import SimpleBar from "simplebar-react";
|
import SimpleBar from "simplebar-react";
|
||||||
|
|
||||||
|
@ -15,6 +15,20 @@ import useSetting from "../../hooks/useSetting";
|
||||||
|
|
||||||
import { useParty } from "../../contexts/PartyContext";
|
import { useParty } from "../../contexts/PartyContext";
|
||||||
import { usePlayerState, usePlayerUpdater } from "../../contexts/PlayerContext";
|
import { usePlayerState, usePlayerUpdater } from "../../contexts/PlayerContext";
|
||||||
|
import { DiceRoll } from "../../types/Dice";
|
||||||
|
import {
|
||||||
|
StreamEndEventHandler,
|
||||||
|
StreamStartEventHandler,
|
||||||
|
} from "../../types/Events";
|
||||||
|
import { Timer as TimerType } from "../../types/Timer";
|
||||||
|
|
||||||
|
type PartyProps = {
|
||||||
|
gameId: string;
|
||||||
|
stream: MediaStream | null;
|
||||||
|
partyStreams: Record<string, MediaStream>;
|
||||||
|
onStreamStart: StreamStartEventHandler;
|
||||||
|
onStreamEnd: StreamEndEventHandler;
|
||||||
|
};
|
||||||
|
|
||||||
function Party({
|
function Party({
|
||||||
gameId,
|
gameId,
|
||||||
|
@ -22,33 +36,27 @@ function Party({
|
||||||
partyStreams,
|
partyStreams,
|
||||||
onStreamStart,
|
onStreamStart,
|
||||||
onStreamEnd,
|
onStreamEnd,
|
||||||
}: {
|
}: PartyProps) {
|
||||||
gameId: string;
|
|
||||||
stream;
|
|
||||||
partyStreams;
|
|
||||||
onStreamStart;
|
|
||||||
onStreamEnd;
|
|
||||||
}) {
|
|
||||||
const setPlayerState = usePlayerUpdater();
|
const setPlayerState = usePlayerUpdater();
|
||||||
const playerState = usePlayerState();
|
const playerState = usePlayerState();
|
||||||
const partyState = useParty();
|
const partyState = useParty();
|
||||||
|
|
||||||
const [fullScreen] = useSetting<boolean>("map.fullScreen");
|
const [fullScreen] = useSetting<boolean>("map.fullScreen");
|
||||||
const [shareDice, setShareDice] = useSetting("dice.shareDice");
|
const [shareDice, setShareDice] = useSetting<boolean>("dice.shareDice");
|
||||||
|
|
||||||
function handleTimerStart(newTimer: PartyTimer) {
|
function handleTimerStart(newTimer: TimerType) {
|
||||||
setPlayerState((prevState) => ({ ...prevState, timer: newTimer }));
|
setPlayerState((prevState) => ({ ...prevState, timer: newTimer }));
|
||||||
}
|
}
|
||||||
|
|
||||||
function handleTimerStop() {
|
function handleTimerStop() {
|
||||||
setPlayerState((prevState) => ({ ...prevState, timer: null }));
|
setPlayerState((prevState) => ({ ...prevState, timer: undefined }));
|
||||||
}
|
}
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
let prevTime = performance.now();
|
let prevTime = performance.now();
|
||||||
let request = requestAnimationFrame(update);
|
let request = requestAnimationFrame(update);
|
||||||
let counter = 0;
|
let counter = 0;
|
||||||
function update(time) {
|
function update(time: number) {
|
||||||
request = requestAnimationFrame(update);
|
request = requestAnimationFrame(update);
|
||||||
const deltaTime = time - prevTime;
|
const deltaTime = time - prevTime;
|
||||||
prevTime = time;
|
prevTime = time;
|
||||||
|
@ -57,12 +65,12 @@ function Party({
|
||||||
counter += deltaTime;
|
counter += deltaTime;
|
||||||
// Update timer every second
|
// Update timer every second
|
||||||
if (counter > 1000) {
|
if (counter > 1000) {
|
||||||
const newTimer: PartyTimer = {
|
const newTimer: TimerType = {
|
||||||
...playerState.timer,
|
...playerState.timer,
|
||||||
current: playerState.timer.current - counter,
|
current: playerState.timer.current - counter,
|
||||||
};
|
};
|
||||||
if (newTimer.current < 0) {
|
if (newTimer.current < 0) {
|
||||||
setPlayerState((prevState) => ({ ...prevState, timer: null }));
|
setPlayerState((prevState) => ({ ...prevState, timer: undefined }));
|
||||||
} else {
|
} else {
|
||||||
setPlayerState((prevState) => ({ ...prevState, timer: newTimer }));
|
setPlayerState((prevState) => ({ ...prevState, timer: newTimer }));
|
||||||
}
|
}
|
||||||
|
@ -79,9 +87,9 @@ function Party({
|
||||||
setPlayerState((prevState) => ({ ...prevState, nickname: newNickname }));
|
setPlayerState((prevState) => ({ ...prevState, nickname: newNickname }));
|
||||||
}
|
}
|
||||||
|
|
||||||
function handleDiceRollsChange(newDiceRolls: number[]) {
|
function handleDiceRollsChange(newDiceRolls: DiceRoll[]) {
|
||||||
setPlayerState(
|
setPlayerState(
|
||||||
(prevState: PlayerDice) => ({
|
(prevState) => ({
|
||||||
...prevState,
|
...prevState,
|
||||||
dice: { share: shareDice, rolls: newDiceRolls },
|
dice: { share: shareDice, rolls: newDiceRolls },
|
||||||
}),
|
}),
|
||||||
|
@ -91,7 +99,7 @@ function Party({
|
||||||
|
|
||||||
function handleShareDiceChange(newShareDice: boolean) {
|
function handleShareDiceChange(newShareDice: boolean) {
|
||||||
setShareDice(newShareDice);
|
setShareDice(newShareDice);
|
||||||
setPlayerState((prevState: PlayerInfo) => ({
|
setPlayerState((prevState) => ({
|
||||||
...prevState,
|
...prevState,
|
||||||
dice: { ...prevState.dice, share: newShareDice },
|
dice: { ...prevState.dice, share: newShareDice },
|
||||||
}));
|
}));
|
||||||
|
@ -134,17 +142,16 @@ function Party({
|
||||||
height: "calc(100% - 232px)",
|
height: "calc(100% - 232px)",
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
{/* TODO: check if stream is required here */}
|
|
||||||
<Nickname
|
<Nickname
|
||||||
nickname={`${playerState.nickname} (you)`}
|
nickname={`${playerState.nickname} (you)`}
|
||||||
diceRolls={shareDice && playerState.dice.rolls}
|
diceRolls={shareDice ? playerState.dice.rolls : undefined}
|
||||||
/>
|
/>
|
||||||
{Object.entries(partyState).map(([id, { nickname, dice }]) => (
|
{Object.entries(partyState).map(([id, { nickname, dice }]) => (
|
||||||
<Nickname
|
<Nickname
|
||||||
nickname={nickname}
|
nickname={nickname}
|
||||||
key={id}
|
key={id}
|
||||||
stream={partyStreams[id]}
|
stream={partyStreams[id]}
|
||||||
diceRolls={dice.share && dice.rolls}
|
diceRolls={dice.share ? dice.rolls : undefined}
|
||||||
/>
|
/>
|
||||||
))}
|
))}
|
||||||
{playerState.timer && <Timer timer={playerState.timer} index={0} />}
|
{playerState.timer && <Timer timer={playerState.timer} index={0} />}
|
||||||
|
|
|
@ -1,20 +1,26 @@
|
||||||
import React, { useState } from "react";
|
import { useState } from "react";
|
||||||
import { IconButton, Box, Text } from "theme-ui";
|
import { IconButton, Box, Text } from "theme-ui";
|
||||||
import adapter from "webrtc-adapter";
|
import adapter from "webrtc-adapter";
|
||||||
|
|
||||||
import Link from "../Link";
|
import Link from "../Link";
|
||||||
|
|
||||||
import StartStreamModal from "../../modals/StartStreamModal";
|
import StartStreamModal from "../../modals/StartStreamModal";
|
||||||
|
import {
|
||||||
|
StreamEndEventHandler,
|
||||||
|
StreamStartEventHandler,
|
||||||
|
} from "../../types/Events";
|
||||||
|
|
||||||
|
type StartStreamProps = {
|
||||||
|
onStreamStart: StreamStartEventHandler;
|
||||||
|
onStreamEnd: StreamEndEventHandler;
|
||||||
|
stream: MediaStream | null;
|
||||||
|
};
|
||||||
|
|
||||||
function StartStreamButton({
|
function StartStreamButton({
|
||||||
onStreamStart,
|
onStreamStart,
|
||||||
onStreamEnd,
|
onStreamEnd,
|
||||||
stream,
|
stream,
|
||||||
}: {
|
}: StartStreamProps) {
|
||||||
onStreamStart;
|
|
||||||
onStreamEnd;
|
|
||||||
stream;
|
|
||||||
}) {
|
|
||||||
const [isStreamModalOpoen, setIsStreamModalOpen] = useState(false);
|
const [isStreamModalOpoen, setIsStreamModalOpen] = useState(false);
|
||||||
function openModal() {
|
function openModal() {
|
||||||
setIsStreamModalOpen(true);
|
setIsStreamModalOpen(true);
|
||||||
|
@ -53,7 +59,7 @@ function StartStreamButton({
|
||||||
|
|
||||||
function handleStreamStart() {
|
function handleStreamStart() {
|
||||||
// Must be defined this way in typescript due to open issue - https://github.com/microsoft/TypeScript/issues/33232
|
// Must be defined this way in typescript due to open issue - https://github.com/microsoft/TypeScript/issues/33232
|
||||||
const mediaDevices = navigator.mediaDevices;
|
const mediaDevices: any = navigator.mediaDevices;
|
||||||
mediaDevices
|
mediaDevices
|
||||||
.getDisplayMedia({
|
.getDisplayMedia({
|
||||||
video: true,
|
video: true,
|
||||||
|
@ -63,7 +69,7 @@ function StartStreamButton({
|
||||||
echoCancellation: false,
|
echoCancellation: false,
|
||||||
},
|
},
|
||||||
})
|
})
|
||||||
.then((localStream: { getTracks }) => {
|
.then((localStream: MediaStream) => {
|
||||||
const tracks = localStream.getTracks();
|
const tracks = localStream.getTracks();
|
||||||
|
|
||||||
const hasAudio = tracks.some(
|
const hasAudio = tracks.some(
|
||||||
|
|
|
@ -1,18 +1,25 @@
|
||||||
import React, { useState } from "react";
|
import { useState } from "react";
|
||||||
import { IconButton } from "theme-ui";
|
import { IconButton } from "theme-ui";
|
||||||
|
|
||||||
import StartTimerModal from "../../modals/StartTimerModal";
|
import StartTimerModal from "../../modals/StartTimerModal";
|
||||||
import StartTimerIcon from "../../icons/StartTimerIcon";
|
import StartTimerIcon from "../../icons/StartTimerIcon";
|
||||||
|
import {
|
||||||
|
TimerStartEventHandler,
|
||||||
|
TimerStopEventHandler,
|
||||||
|
} from "../../types/Events";
|
||||||
|
import { Timer } from "../../types/Timer";
|
||||||
|
|
||||||
|
type StartTimerButtonProps = {
|
||||||
|
onTimerStart: TimerStartEventHandler;
|
||||||
|
onTimerStop: TimerStopEventHandler;
|
||||||
|
timer?: Timer;
|
||||||
|
};
|
||||||
|
|
||||||
function StartTimerButton({
|
function StartTimerButton({
|
||||||
onTimerStart,
|
onTimerStart,
|
||||||
onTimerStop,
|
onTimerStop,
|
||||||
timer,
|
timer,
|
||||||
}: {
|
}: StartTimerButtonProps) {
|
||||||
onTimerStart;
|
|
||||||
onTimerStop;
|
|
||||||
timer;
|
|
||||||
}) {
|
|
||||||
const [isTimerModalOpen, setIsTimerModalOpen] = useState(false);
|
const [isTimerModalOpen, setIsTimerModalOpen] = useState(false);
|
||||||
|
|
||||||
function openModal() {
|
function openModal() {
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
import React, { useState, useRef, useEffect, ChangeEvent } from "react";
|
import { useState, useRef, useEffect, ChangeEvent } from "react";
|
||||||
import { Text, IconButton, Box, Flex } from "theme-ui";
|
import { Text, IconButton, Box, Flex } from "theme-ui";
|
||||||
|
|
||||||
import StreamMuteIcon from "../../icons/StreamMuteIcon";
|
import StreamMuteIcon from "../../icons/StreamMuteIcon";
|
||||||
|
@ -6,18 +6,17 @@ import StreamMuteIcon from "../../icons/StreamMuteIcon";
|
||||||
import Banner from "../banner/Banner";
|
import Banner from "../banner/Banner";
|
||||||
import Slider from "../Slider";
|
import Slider from "../Slider";
|
||||||
|
|
||||||
function Stream({
|
type StreamProps = {
|
||||||
stream,
|
|
||||||
nickname,
|
|
||||||
}: {
|
|
||||||
stream: MediaStream;
|
stream: MediaStream;
|
||||||
nickname: string;
|
nickname: string;
|
||||||
}) {
|
};
|
||||||
|
|
||||||
|
function Stream({ stream, nickname }: StreamProps) {
|
||||||
const [streamVolume, setStreamVolume] = useState(1);
|
const [streamVolume, setStreamVolume] = useState(1);
|
||||||
const [showStreamInteractBanner, setShowStreamInteractBanner] =
|
const [showStreamInteractBanner, setShowStreamInteractBanner] =
|
||||||
useState(false);
|
useState(false);
|
||||||
const [streamMuted, setStreamMuted] = useState(false);
|
const [streamMuted, setStreamMuted] = useState(false);
|
||||||
const audioRef = useRef();
|
const audioRef = useRef<HTMLAudioElement>(null);
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (audioRef.current) {
|
if (audioRef.current) {
|
||||||
|
@ -59,17 +58,21 @@ function Stream({
|
||||||
const [isVolumeControlAvailable, setIsVolumeControlAvailable] =
|
const [isVolumeControlAvailable, setIsVolumeControlAvailable] =
|
||||||
useState(true);
|
useState(true);
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
let audio = audioRef.current;
|
const audio = audioRef.current;
|
||||||
function checkVolumeControlAvailable() {
|
if (!audio) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
const checkVolumeControlAvailable = () => {
|
||||||
const prevVolume = audio.volume;
|
const prevVolume = audio.volume;
|
||||||
// Set volume to 0.5, then check if the value actually stuck 100ms later
|
// Set volume to 0.5, then check if the value actually stuck 100ms later
|
||||||
audio.volume = 0.5;
|
audio.volume = 0.5;
|
||||||
setTimeout(() => {
|
setTimeout(() => {
|
||||||
setIsVolumeControlAvailable(audio.volume === 0.5);
|
if (audio) {
|
||||||
audio.volume = prevVolume;
|
setIsVolumeControlAvailable(audio.volume === 0.5);
|
||||||
// TODO: check if this supposed to be a number or number[]
|
audio.volume = prevVolume;
|
||||||
|
}
|
||||||
}, 100);
|
}, 100);
|
||||||
}
|
};
|
||||||
|
|
||||||
audio.addEventListener("playing", checkVolumeControlAvailable);
|
audio.addEventListener("playing", checkVolumeControlAvailable);
|
||||||
|
|
||||||
|
@ -79,7 +82,7 @@ function Stream({
|
||||||
}, []);
|
}, []);
|
||||||
|
|
||||||
// Use an audio context gain node to control volume to go past 100%
|
// Use an audio context gain node to control volume to go past 100%
|
||||||
const audioGainRef = useRef();
|
const audioGainRef = useRef<GainNode>();
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
let audioContext: AudioContext;
|
let audioContext: AudioContext;
|
||||||
if (stream && !streamMuted && isVolumeControlAvailable && audioGainRef) {
|
if (stream && !streamMuted && isVolumeControlAvailable && audioGainRef) {
|
||||||
|
|
|
@ -1,11 +1,17 @@
|
||||||
import React, { useEffect, useRef } from "react";
|
import { useEffect, useRef } from "react";
|
||||||
import ReactDOM from "react-dom";
|
import ReactDOM from "react-dom";
|
||||||
import { Box, Progress } from "theme-ui";
|
import { Box, Progress } from "theme-ui";
|
||||||
|
|
||||||
import usePortal from "../../hooks/usePortal";
|
import usePortal from "../../hooks/usePortal";
|
||||||
|
import { Timer as TimerType } from "../../types/Timer";
|
||||||
|
|
||||||
function Timer({ timer, index }: { timer; index: number }) {
|
type TimerProps = {
|
||||||
const progressBarRef = useRef();
|
timer?: TimerType;
|
||||||
|
index: number;
|
||||||
|
};
|
||||||
|
|
||||||
|
function Timer({ timer, index }: TimerProps) {
|
||||||
|
const progressBarRef = useRef<HTMLProgressElement>(null);
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (progressBarRef.current && timer) {
|
if (progressBarRef.current && timer) {
|
||||||
|
@ -16,7 +22,7 @@ function Timer({ timer, index }: { timer; index: number }) {
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
let request = requestAnimationFrame(animate);
|
let request = requestAnimationFrame(animate);
|
||||||
let previousTime = performance.now();
|
let previousTime = performance.now();
|
||||||
function animate(time) {
|
function animate(time: number) {
|
||||||
request = requestAnimationFrame(animate);
|
request = requestAnimationFrame(animate);
|
||||||
const deltaTime = time - previousTime;
|
const deltaTime = time - previousTime;
|
||||||
previousTime = time;
|
previousTime = time;
|
||||||
|
|
|
@ -23,7 +23,6 @@ export type CustomDragEndEvent = DragEndWithOverlayEvent & DragEndEvent;
|
||||||
|
|
||||||
type CustomDragProps = {
|
type CustomDragProps = {
|
||||||
onDragEnd?: (event: CustomDragEndEvent) => void;
|
onDragEnd?: (event: CustomDragEndEvent) => void;
|
||||||
;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
function DragPositionMonitor({ onDragEnd }: CustomDragProps) {
|
function DragPositionMonitor({ onDragEnd }: CustomDragProps) {
|
||||||
|
|
|
@ -66,21 +66,25 @@ export const GridCellPixelOffsetContext = React.createContext(
|
||||||
|
|
||||||
const defaultStrokeWidth = 1 / 10;
|
const defaultStrokeWidth = 1 / 10;
|
||||||
|
|
||||||
|
type GridProviderProps = {
|
||||||
|
grid: Grid | null;
|
||||||
|
width: number;
|
||||||
|
height: number;
|
||||||
|
children: React.ReactNode;
|
||||||
|
};
|
||||||
|
|
||||||
export function GridProvider({
|
export function GridProvider({
|
||||||
grid: inputGrid,
|
grid: inputGrid,
|
||||||
width,
|
width,
|
||||||
height,
|
height,
|
||||||
children,
|
children,
|
||||||
}: {
|
}: GridProviderProps) {
|
||||||
grid: Grid;
|
let grid: Grid;
|
||||||
width: number;
|
|
||||||
height: number;
|
|
||||||
children: React.ReactNode;
|
|
||||||
}) {
|
|
||||||
let grid = inputGrid;
|
|
||||||
|
|
||||||
if (!grid.size.x || !grid.size.y) {
|
if (!inputGrid || !inputGrid.size.x || !inputGrid.size.y) {
|
||||||
grid = defaultValue.grid;
|
grid = defaultValue.grid;
|
||||||
|
} else {
|
||||||
|
grid = inputGrid;
|
||||||
}
|
}
|
||||||
|
|
||||||
const [gridPixelSize, setGridPixelSize] = useState(
|
const [gridPixelSize, setGridPixelSize] = useState(
|
||||||
|
|
|
@ -359,24 +359,22 @@ export function gridDistance(
|
||||||
* @returns {GridScale}
|
* @returns {GridScale}
|
||||||
*/
|
*/
|
||||||
|
|
||||||
export function parseGridScale(scale: string): GridScale {
|
export function parseGridScale(scale: string | null): GridScale {
|
||||||
if (typeof scale === "string") {
|
if (typeof scale === "string") {
|
||||||
const match = scale.match(/(\d*)(\.\d*)?([a-zA-Z]*)/);
|
const match = scale.match(/(\d*)(\.\d*)?([a-zA-Z]*)/);
|
||||||
// TODO: handle case where match is not found
|
if (match) {
|
||||||
if (!match) {
|
const integer = parseFloat(match[1]);
|
||||||
throw Error;
|
const fractional = parseFloat(match[2]);
|
||||||
}
|
const unit = match[3] || "";
|
||||||
const integer = parseFloat(match[1]);
|
if (!isNaN(integer) && !isNaN(fractional)) {
|
||||||
const fractional = parseFloat(match[2]);
|
return {
|
||||||
const unit = match[3] || "";
|
multiplier: integer + fractional,
|
||||||
if (!isNaN(integer) && !isNaN(fractional)) {
|
unit: unit,
|
||||||
return {
|
digits: match[2].length - 1,
|
||||||
multiplier: integer + fractional,
|
};
|
||||||
unit: unit,
|
} else if (!isNaN(integer) && isNaN(fractional)) {
|
||||||
digits: match[2].length - 1,
|
return { multiplier: integer, unit: unit, digits: 0 };
|
||||||
};
|
}
|
||||||
} else if (!isNaN(integer) && isNaN(fractional)) {
|
|
||||||
return { multiplier: integer, unit: unit, digits: 0 };
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return { multiplier: 1, unit: "", digits: 0 };
|
return { multiplier: 1, unit: "", digits: 0 };
|
||||||
|
|
|
@ -2,20 +2,22 @@ import { Box, Text, Button, Label, Flex } from "theme-ui";
|
||||||
|
|
||||||
import Modal from "../components/Modal";
|
import Modal from "../components/Modal";
|
||||||
|
|
||||||
import { RequestCloseEventHandler } from "../types/Events";
|
import {
|
||||||
|
RequestCloseEventHandler,
|
||||||
|
StreamEndEventHandler,
|
||||||
|
} from "../types/Events";
|
||||||
|
|
||||||
export type StreamStartEventHandler = () => void;
|
export type StreamOpenAndStartEventHandler = () => void;
|
||||||
export type StreamEndEventHandler = (stream: MediaStream) => void;
|
|
||||||
|
|
||||||
type StartStreamProps = {
|
type StartStreamProps = {
|
||||||
isOpen: boolean;
|
isOpen: boolean;
|
||||||
onRequestClose: RequestCloseEventHandler;
|
onRequestClose: RequestCloseEventHandler;
|
||||||
isSupported: boolean;
|
isSupported: boolean;
|
||||||
unavailableMessage: JSX.Element;
|
unavailableMessage: JSX.Element;
|
||||||
stream: MediaStream;
|
stream: MediaStream | null;
|
||||||
noAudioTrack: boolean;
|
noAudioTrack: boolean;
|
||||||
noAudioMessage: JSX.Element;
|
noAudioMessage: JSX.Element;
|
||||||
onStreamStart: StreamStartEventHandler;
|
onStreamStart: StreamOpenAndStartEventHandler;
|
||||||
onStreamEnd: StreamEndEventHandler;
|
onStreamEnd: StreamEndEventHandler;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -7,12 +7,13 @@ import { getHMSDuration, getDurationHMS } from "../helpers/timer";
|
||||||
|
|
||||||
import useSetting from "../hooks/useSetting";
|
import useSetting from "../hooks/useSetting";
|
||||||
|
|
||||||
import { RequestCloseEventHandler } from "../types/Events";
|
import {
|
||||||
|
RequestCloseEventHandler,
|
||||||
|
TimerStartEventHandler,
|
||||||
|
TimerStopEventHandler,
|
||||||
|
} from "../types/Events";
|
||||||
import { Timer } from "../types/Timer";
|
import { Timer } from "../types/Timer";
|
||||||
|
|
||||||
export type TimerStartEventHandler = (event: Timer) => void;
|
|
||||||
export type TimerStopEventHandler = () => void;
|
|
||||||
|
|
||||||
type StartTimerProps = {
|
type StartTimerProps = {
|
||||||
isOpen: boolean;
|
isOpen: boolean;
|
||||||
onRequestClose: RequestCloseEventHandler;
|
onRequestClose: RequestCloseEventHandler;
|
||||||
|
|
|
@ -1,8 +1,9 @@
|
||||||
import Konva from "konva";
|
import Konva from "konva";
|
||||||
import { DefaultDice } from "./Dice";
|
import { DefaultDice, DiceRoll } from "./Dice";
|
||||||
import { Map } from "./Map";
|
import { Map } from "./Map";
|
||||||
import { MapState } from "./MapState";
|
import { MapState } from "./MapState";
|
||||||
import { Note } from "./Note";
|
import { Note } from "./Note";
|
||||||
|
import { Timer } from "./Timer";
|
||||||
import { Token } from "./Token";
|
import { Token } from "./Token";
|
||||||
import { TokenState } from "./TokenState";
|
import { TokenState } from "./TokenState";
|
||||||
|
|
||||||
|
@ -43,3 +44,12 @@ export type NoteDragEventHandler = (
|
||||||
event: Konva.KonvaEventObject<DragEvent>,
|
event: Konva.KonvaEventObject<DragEvent>,
|
||||||
noteId: string
|
noteId: string
|
||||||
) => void;
|
) => void;
|
||||||
|
|
||||||
|
export type DiceShareChangeEventHandler = (share: boolean) => void;
|
||||||
|
export type DiceRollsChangeEventHandler = (newRolls: DiceRoll[]) => void;
|
||||||
|
|
||||||
|
export type StreamStartEventHandler = (stream: MediaStream) => void;
|
||||||
|
export type StreamEndEventHandler = (stream: MediaStream) => void;
|
||||||
|
|
||||||
|
export type TimerStartEventHandler = (event: Timer) => void;
|
||||||
|
export type TimerStopEventHandler = () => void;
|
||||||
|
|
|
@ -22,7 +22,10 @@ import { Group, GroupContainer } from "./types/Group";
|
||||||
|
|
||||||
export type UpgradeEventHandler = (versionNumber: number) => void;
|
export type UpgradeEventHandler = (versionNumber: number) => void;
|
||||||
|
|
||||||
type VersionCallback = (version: Version, onUpgrade?: UpgradeEventHandler);
|
type VersionCallback = (
|
||||||
|
version: Version,
|
||||||
|
onUpgrade?: UpgradeEventHandler
|
||||||
|
) => void;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Mapping of version number to their upgrade function
|
* Mapping of version number to their upgrade function
|
||||||
|
@ -285,7 +288,7 @@ export const versions: Record<number, VersionCallback> = {
|
||||||
v.stores({}).upgrade(async (tx) => {
|
v.stores({}).upgrade(async (tx) => {
|
||||||
onUpgrade?.(15);
|
onUpgrade?.(15);
|
||||||
const tokens = await Dexie.waitFor(tx.table("tokens").toArray());
|
const tokens = await Dexie.waitFor(tx.table("tokens").toArray());
|
||||||
let tokenSizes: Record<string, {width: number, height: number}> = {};
|
let tokenSizes: Record<string, { width: number; height: number }> = {};
|
||||||
for (let token of tokens) {
|
for (let token of tokens) {
|
||||||
const url = URL.createObjectURL(new Blob([token.file]));
|
const url = URL.createObjectURL(new Blob([token.file]));
|
||||||
let image = new Image();
|
let image = new Image();
|
||||||
|
@ -775,7 +778,7 @@ export const versions: Record<number, VersionCallback> = {
|
||||||
34(v, onUpgrade) {
|
34(v, onUpgrade) {
|
||||||
v.stores({ groups: "id" }).upgrade(async (tx) => {
|
v.stores({ groups: "id" }).upgrade(async (tx) => {
|
||||||
onUpgrade?.(34);
|
onUpgrade?.(34);
|
||||||
function groupItems(items: {id: string, group: string}[]) {
|
function groupItems(items: { id: string; group: string }[]) {
|
||||||
let groups: Group[] = [];
|
let groups: Group[] = [];
|
||||||
let subGroups: Record<string, GroupContainer> = {};
|
let subGroups: Record<string, GroupContainer> = {};
|
||||||
for (let item of items) {
|
for (let item of items) {
|
||||||
|
@ -841,7 +844,11 @@ export const latestVersion = 36;
|
||||||
* @param {number=} upTo version number to load up to, latest version if undefined
|
* @param {number=} upTo version number to load up to, latest version if undefined
|
||||||
* @param {UpgradeEventHandler=} onUpgrade
|
* @param {UpgradeEventHandler=} onUpgrade
|
||||||
*/
|
*/
|
||||||
export function loadVersions(db: Dexie, upTo: number | undefined = latestVersion, onUpgrade: UpgradeEventHandler | undefined) {
|
export function loadVersions(
|
||||||
|
db: Dexie,
|
||||||
|
upTo: number | undefined = latestVersion,
|
||||||
|
onUpgrade: UpgradeEventHandler | undefined
|
||||||
|
) {
|
||||||
for (let versionNumber = 1; versionNumber <= upTo; versionNumber++) {
|
for (let versionNumber = 1; versionNumber <= upTo; versionNumber++) {
|
||||||
versions[versionNumber](db.version(versionNumber), onUpgrade);
|
versions[versionNumber](db.version(versionNumber), onUpgrade);
|
||||||
}
|
}
|
||||||
|
@ -883,12 +890,12 @@ function convertOldActionsToShapes(actions: any[], actionIndex: number) {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Helper to create a thumbnail for a file in a db
|
// Helper to create a thumbnail for a file in a db
|
||||||
async function createDataThumbnail(data: any) : Promise<{
|
async function createDataThumbnail(data: any): Promise<{
|
||||||
file: Uint8Array,
|
file: Uint8Array;
|
||||||
width: number,
|
width: number;
|
||||||
height: number,
|
height: number;
|
||||||
type: "file",
|
type: "file";
|
||||||
id: "thumbnail",
|
id: "thumbnail";
|
||||||
}> {
|
}> {
|
||||||
let url: string;
|
let url: string;
|
||||||
if (data?.resolutions?.low?.file) {
|
if (data?.resolutions?.low?.file) {
|
||||||
|
@ -917,7 +924,9 @@ async function createDataThumbnail(data: any) : Promise<{
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
async function createDataOutline(data: any) : Promise<{id: string, outline: Outline}> {
|
async function createDataOutline(
|
||||||
|
data: any
|
||||||
|
): Promise<{ id: string; outline: Outline }> {
|
||||||
const url = URL.createObjectURL(new Blob([data.file]));
|
const url = URL.createObjectURL(new Blob([data.file]));
|
||||||
return await Dexie.waitFor(
|
return await Dexie.waitFor(
|
||||||
new Promise((resolve) => {
|
new Promise((resolve) => {
|
||||||
|
|
|
@ -3069,6 +3069,13 @@
|
||||||
resolved "https://registry.yarnpkg.com/@types/json5/-/json5-0.0.29.tgz#ee28707ae94e11d2b827bcbe5270bcea7f3e71ee"
|
resolved "https://registry.yarnpkg.com/@types/json5/-/json5-0.0.29.tgz#ee28707ae94e11d2b827bcbe5270bcea7f3e71ee"
|
||||||
integrity sha1-7ihweulOEdK4J7y+UnC86n8+ce4=
|
integrity sha1-7ihweulOEdK4J7y+UnC86n8+ce4=
|
||||||
|
|
||||||
|
"@types/lodash.chunk@^4.2.6":
|
||||||
|
version "4.2.6"
|
||||||
|
resolved "https://registry.yarnpkg.com/@types/lodash.chunk/-/lodash.chunk-4.2.6.tgz#9d35f05360b0298715d7f3d9efb34dd4f77e5d2a"
|
||||||
|
integrity sha512-SPlusB7jxXyGcTXYcUdWr7WmhArO/rmTq54VN88iKMxGUhyg79I4Q8n4riGn3kjaTjOJrVlHhxgX/d7woak5BQ==
|
||||||
|
dependencies:
|
||||||
|
"@types/lodash" "*"
|
||||||
|
|
||||||
"@types/lodash.clonedeep@^4.5.6":
|
"@types/lodash.clonedeep@^4.5.6":
|
||||||
version "4.5.6"
|
version "4.5.6"
|
||||||
resolved "https://registry.yarnpkg.com/@types/lodash.clonedeep/-/lodash.clonedeep-4.5.6.tgz#3b6c40a0affe0799a2ce823b440a6cf33571d32b"
|
resolved "https://registry.yarnpkg.com/@types/lodash.clonedeep/-/lodash.clonedeep-4.5.6.tgz#3b6c40a0affe0799a2ce823b440a6cf33571d32b"
|
||||||
|
|
Loading…
Reference in New Issue
Block a user