Skip to content

Commit

Permalink
Merge pull request #443 from scottbenton/feat/oracle-match-reminder
Browse files Browse the repository at this point in the history
Feat/oracle match reminder
  • Loading branch information
scottbenton authored May 24, 2024
2 parents e374785 + 53908b6 commit aefa331
Show file tree
Hide file tree
Showing 19 changed files with 462 additions and 38 deletions.
13 changes: 13 additions & 0 deletions CHANGELOG.MD
Original file line number Diff line number Diff line change
@@ -1,5 +1,18 @@
# Changelog

## 3.1.0

### New Features

- Added a match reminder to the roll display for oracle rolls that care about dice matching (ask the oracle moves)
- Added asset clock and counter controls working for assets that use them (ex: Snub Fighter Ability #3, or Marked Ability #2).

### Changes

- Re-added missing roll buttons for assets in the move dialog

### Bug Fixes

## 3.0.0

### New Features
Expand Down
3 changes: 2 additions & 1 deletion src/components/features/ProgressTrack/ProgressTrack.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -139,7 +139,8 @@ export function ProgressTrack(props: ProgressTracksProps) {
rollTrackProgress(
trackType,
label || "",
Math.min(Math.floor(value / 4), 10)
Math.min(Math.floor(value / 4), 10),
move?._id ?? ""
);
}
};
Expand Down
38 changes: 36 additions & 2 deletions src/components/features/assets/AssetCard/AssetCard.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import { AssetControls } from "./AssetControls";
import { AssetHeader } from "./AssetHeader";
import { AssetNameAndDescription } from "./AssetNameAndDescription";
import { ForwardedRef, ReactNode, forwardRef } from "react";
import { Datasworn } from "@datasworn/core";

export interface AssetCardProps {
assetId: string;
Expand Down Expand Up @@ -49,6 +50,39 @@ const AssetCardComponent = (
return null;
}

const assetControls: Record<
string,
Datasworn.AssetControlField | Datasworn.AssetAbilityControlField
> = { ...asset.controls };
const assetOptions = { ...asset.options };

asset.abilities.forEach((ability, index) => {
const isEnabled = ability.enabled || storedAsset?.enabledAbilities[index];

if (isEnabled) {
const controls = ability.controls ?? {};
const options = ability.options ?? {};
Object.keys(controls).forEach((controlKey) => {
assetControls[controlKey] = controls[controlKey];
});
Object.keys(options).forEach((optionKey) => {
assetOptions[optionKey] = options[optionKey];
});

const enhanceControls = ability.enhance_asset?.controls ?? {};
Object.keys(enhanceControls).forEach((controlKey) => {
const enhancement = enhanceControls[controlKey];
const assetControl = assetControls[controlKey];
if (assetControl?.field_type === enhancement.field_type) {
assetControls[controlKey] = {
...assetControl,
...(enhancement as Partial<typeof assetControl>),
};
}
});
}
});

return (
<Card
ref={ref}
Expand Down Expand Up @@ -79,7 +113,7 @@ const AssetCardComponent = (
showSharedIcon={showSharedIcon}
/>
<AssetOptions
asset={asset}
options={assetOptions}
storedAsset={storedAsset}
onAssetOptionChange={onAssetOptionChange}
/>
Expand All @@ -89,7 +123,7 @@ const AssetCardComponent = (
onAbilityToggle={onAssetAbilityToggle}
/>
<AssetControls
controls={asset.controls}
controls={assetControls}
storedAsset={storedAsset}
onControlChange={onAssetControlChange}
/>
Expand Down
47 changes: 46 additions & 1 deletion src/components/features/assets/AssetCard/AssetControl.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -11,10 +11,12 @@ import {
import { Track } from "components/features/Track";
import { AssetControls } from "./AssetControls";
import { AssetDocument } from "api-calls/assets/_asset.type";
import { AssetControlCounter } from "./AssetControlCounter";
import { AssetControlClock } from "./AssetControlClock";

export interface AssetControlProps {
controlId: string;
control: Datasworn.AssetControlField;
control: Datasworn.AssetControlField | Datasworn.AssetAbilityControlField;
storedAsset?: AssetDocument;
onControlChange?: (
controlKey: string,
Expand Down Expand Up @@ -147,6 +149,49 @@ export function AssetControl(props: AssetControlProps) {
</Box>
);
}
case "text": {
return (
<TextField
label={capitalize(control.label)}
defaultValue={
storedAsset?.controlValues?.[controlId] ?? control.value ?? ""
}
disabled={!onControlChange}
onChange={(evt) =>
onControlChange && onControlChange(controlId, evt.target.value)
}
variant={"standard"}
sx={{ mt: 0.5 }}
fullWidth
/>
);
}
case "clock": {
return (
<AssetControlClock
field={control}
value={typeof controlValue === "number" ? controlValue : undefined}
onChange={
onControlChange
? (value) => onControlChange(controlId, value)
: undefined
}
/>
);
}
case "counter": {
return (
<AssetControlCounter
value={typeof controlValue === "number" ? controlValue : undefined}
field={control}
onChange={
onControlChange
? (value) => onControlChange(controlId, value)
: undefined
}
/>
);
}
}

return null;
Expand Down
55 changes: 55 additions & 0 deletions src/components/features/assets/AssetCard/AssetControlClock.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
import { Datasworn } from "@datasworn/core";
import { Box, Typography } from "@mui/material";
import { useDebouncedState } from "hooks/useDebouncedState";
import { useStore } from "stores/store";
import { ClockCircle } from "components/features/charactersAndCampaigns/Clocks/ClockCircle";

export interface AssetControlClockProps {
value?: number;
field: Datasworn.ClockField;
onChange?: (value: number) => void;
}

export function AssetControlClock(props: AssetControlClockProps) {
const { value, field, onChange } = props;

const [localValue, setLocalValue] = useDebouncedState<number>(
(value) => onChange && onChange(value),
value ?? field.value,
500
);

const announce = useStore((store) => store.appState.announce);

const handleIncrement = () => {
setLocalValue((prev) => {
const newValue = prev + 1;
if (typeof field.max === "number" && field.max < newValue) {
announce(
`Cannot increase ${field.label} beyond ${field.max}. Resetting field to 0`
);
return 0;
}
announce(`Increased ${field.label} by 1 for a total of ${newValue}`);
return newValue;
});
};

return (
<Box>
<Typography
variant={"subtitle1"}
fontFamily={(theme) => theme.fontFamilyTitle}
color={"textSecondary"}
>
{field.label}
</Typography>

<ClockCircle
value={localValue}
segments={field.max}
onClick={handleIncrement}
/>
</Box>
);
}
131 changes: 131 additions & 0 deletions src/components/features/assets/AssetCard/AssetControlCounter.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,131 @@
import { Datasworn } from "@datasworn/core";
import { Box, ButtonBase, Typography } from "@mui/material";
import { useDebouncedState } from "hooks/useDebouncedState";
import { useStore } from "stores/store";
import AddIcon from "@mui/icons-material/Add";
import SubtractIcon from "@mui/icons-material/Remove";

export interface AssetControlCounterProps {
value?: number;
field: Datasworn.CounterField;
onChange?: (value: number) => void;
}

export function AssetControlCounter(props: AssetControlCounterProps) {
const { value, field, onChange } = props;

const [localValue, setLocalValue] = useDebouncedState<number>(
(value) => onChange && onChange(value),
value ?? field.value,
500
);

const announce = useStore((store) => store.appState.announce);

const handleDecrement = () => {
setLocalValue((prev) => {
const newValue = prev - 1;
if (typeof field.min === "number" && field.min > newValue) {
announce(`Cannot decrease ${field.label} beyond ${field.max}`);
return prev;
}
announce(`Decreased ${field.label} by 1 for a total of ${newValue}`);
return newValue;
});
};

const handleIncrement = () => {
setLocalValue((prev) => {
const newValue = prev + 1;
if (typeof field.max === "number" && field.max < newValue) {
announce(`Cannot increase ${field.label} beyond ${field.max}`);
return prev;
}
announce(`Increased ${field.label} by 1 for a total of ${newValue}`);
return newValue;
});
};

return (
<div>
<Box
display={"inline-flex"}
alignItems={"stretch"}
border={`1px solid`}
borderColor={"divider"}
borderRadius={1}
overflow={"hidden"}
>
<Typography
variant={"subtitle1"}
fontFamily={(theme) => theme.fontFamilyTitle}
sx={(theme) => ({
bgcolor: (theme) =>
theme.palette.mode === "light"
? theme.palette.darkGrey.light
: theme.palette.grey[400],
color:
theme.palette.mode === "light"
? theme.palette.darkGrey.contrastText
: theme.palette.grey[800],
px: 0.5,
})}
>
{field.label}
</Typography>
{onChange && (
<ButtonBase
aria-label={`Decrement ${field.label}`}
onClick={handleDecrement}
sx={(theme) => ({
bgcolor: theme.palette.mode === "light" ? "grey.300" : "grey.600",
color: theme.palette.mode === "light" ? "grey.700" : "grey.200",
transition: theme.transitions.create(["background-color"], {
duration: theme.transitions.duration.shortest,
}),
"&:hover": {
bgcolor:
theme.palette.mode === "light" ? "grey.400" : "grey.700",
},
})}
>
<SubtractIcon />
</ButtonBase>
)}

<Typography
component={"p"}
color={"textSecondary"}
sx={{
fontWeight: 600,
alignSelf: "center",
textAlign: "center",
width: 64,
}}
>
{localValue > 0 ? "+" : ""}
{localValue}
</Typography>
{onChange && (
<ButtonBase
aria-label={`Increment ${field.label}`}
onClick={handleIncrement}
sx={(theme) => ({
bgcolor: theme.palette.mode === "light" ? "grey.300" : "grey.600",
color: theme.palette.mode === "light" ? "grey.700" : "grey.200",
transition: theme.transitions.create(["background-color"], {
duration: theme.transitions.duration.shortest,
}),
"&:hover": {
bgcolor:
theme.palette.mode === "light" ? "grey.400" : "grey.700",
},
})}
>
<AddIcon />
</ButtonBase>
)}
</Box>
</div>
);
}
7 changes: 6 additions & 1 deletion src/components/features/assets/AssetCard/AssetControls.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,12 @@ import { AssetControl } from "./AssetControl";
import { Stack } from "@mui/material";

export interface AssetControlsProps {
controls: Record<string, Datasworn.AssetControlField> | undefined;
controls:
| Record<
string,
Datasworn.AssetControlField | Datasworn.AssetAbilityControlField
>
| undefined;
storedAsset?: AssetDocument;
row?: boolean;
onControlChange?: (
Expand Down
Loading

0 comments on commit aefa331

Please sign in to comment.