diff --git a/src/assets/asset-card.ts b/src/assets/asset-card.ts
index 4bb448bb..729daf67 100644
--- a/src/assets/asset-card.ts
+++ b/src/assets/asset-card.ts
@@ -1,23 +1,29 @@
import {
Asset,
AssetAbility,
+ AssetAbilityControlField,
AssetConditionMeter,
AssetControlField,
AssetOptionField,
DictKey,
} from "@datasworn/core/dist/Datasworn";
-import { TemplateResult, html } from "lit-html";
+import { TemplateResult, html, nothing } from "lit-html";
import { map } from "lit-html/directives/map.js";
import { range } from "lit-html/directives/range.js";
+import { Clock } from "clocks/clock";
+import { clockWidget } from "clocks/ui/clock-widget";
import { IDataContext } from "datastore/data-context";
import { produce } from "immer";
import IronVaultPlugin from "index";
import { repeat } from "lit-html/directives/repeat.js";
+import { rootLogger } from "logger";
import { md } from "utils/ui/directives";
import { integratedAssetLens } from "../characters/assets";
import { IronVaultSheetAssetSchema } from "../characters/lens";
+const logger = rootLogger.getLogger("asset-card");
+
export function makeDefaultSheetAsset(asset: Asset) {
return {
id: asset._id,
@@ -194,6 +200,14 @@ function renderAssetAbility(
}),
);
};
+ const updateControlField = (key: string) =>
+ updateAsset &&
+ ((control: AssetAbilityControlField) =>
+ updateAsset(
+ produce(asset, (draft) => {
+ draft.abilities[i].controls![key] = control;
+ }),
+ ));
return html`
+ ${ability.controls
+ ? html`
+ ${repeat(
+ Object.entries(ability.controls),
+ ([key]) => key,
+ ([key, control]) => {
+ return html`-
+
+ - ${key}
+ -
+ ${renderControl(key, control, updateControlField(key))}
+
+
+ `;
+ },
+ )}
+
`
+ : null}
`;
}
@@ -242,10 +274,10 @@ function renderControls(
`;
}
-function renderControl(
+function renderControl(
key: string,
- control: AssetControlField,
- updateControl?: (asset: AssetControlField) => void,
+ control: C,
+ updateControl?: (control: C) => void,
) {
const updateControlValue = (e: Event) => {
const value = (e.target as HTMLInputElement).value;
@@ -275,6 +307,14 @@ function renderControl(
}),
);
};
+ const updateClockValue = (newProgress: number) => {
+ if (!updateControl) return;
+ updateControl(
+ produce(control, (draft) => {
+ draft.value = newProgress;
+ }),
+ );
+ };
switch (control.field_type) {
case "condition_meter": {
@@ -283,7 +323,12 @@ function renderControl(
@submit=${(ev: Event) => ev.preventDefault()}
>
${control.controls &&
- renderControls(control, control.controls, updateControl)}
+ renderControls(
+ control,
+ control.controls,
+ // At this point we know this must be an updater for a condition meter
+ updateControl as (control: AssetConditionMeter) => void,
+ )}
- ${control.label}
${repeat(
@@ -359,5 +404,43 @@ function renderControl(
`;
}
+
+ case "clock": {
+ return clockWidget(
+ Clock.create({
+ active: true,
+ name: control.label,
+ progress: control.value,
+ segments: control.max,
+ }).unwrap(),
+ updateClockValue,
+ );
+ }
+ case "counter": {
+ return html``;
+ }
+
+ case "text": {
+ return html``;
+ }
+ default:
+ logger.warn(
+ "Unsupported asset control: %s",
+ (control as { field_type: string }).field_type,
+ );
+ return html``;
}
}
diff --git a/src/assets/css/asset-card.css b/src/assets/css/asset-card.css
index 5f00152f..18ebbb47 100644
--- a/src/assets/css/asset-card.css
+++ b/src/assets/css/asset-card.css
@@ -228,4 +228,9 @@
}
}
}
+
+ & input[type=number]::-webkit-inner-spin-button {
+ appearance: auto;
+ -webkit-appearance: auto;
+ }
}
diff --git a/src/clocks/clock-block.ts b/src/clocks/clock-block.ts
index ffbd8ad2..14b61b3c 100644
--- a/src/clocks/clock-block.ts
+++ b/src/clocks/clock-block.ts
@@ -1,6 +1,4 @@
-import { html, render, svg } from "lit-html";
-import { map } from "lit-html/directives/map.js";
-import { range } from "lit-html/directives/range.js";
+import { html, render } from "lit-html";
import IronVaultPlugin from "index";
import { vaultProcess } from "utils/obsidian";
@@ -9,6 +7,7 @@ import { TrackedEntityRenderer } from "utils/ui/tracked-entity-renderer";
import { ZodError } from "zod";
import { Clock } from "./clock";
import { ClockFileAdapter, clockUpdater } from "./clock-file";
+import { clockWidget } from "./ui/clock-widget";
export default function registerClockBlock(plugin: IronVaultPlugin): void {
plugin.registerMarkdownCodeBlockProcessor(
@@ -74,19 +73,11 @@ class ClockRenderer extends TrackedEntityRenderer {
>`}
-
+ ${clockWidget(clockFile.clock, (newProgress) =>
+ this.updateClockProgress({
+ progress: newProgress,
+ }),
+ )}
{
render(tpl, this.containerEl);
}
- renderPath(i: number, clockFile: ClockFileAdapter) {
- return svg`
this.updateClockProgress({ progress: i === 0 && clockFile.clock.progress === 1 ? 0 : i + 1 })}
- >`;
- }
-
async updateClockProgress({
steps,
progress,
@@ -174,16 +156,3 @@ class ClockRenderer extends TrackedEntityRenderer
{
);
}
}
-
-const R = 50;
-
-function pathString(wedgeIdx: number, numWedges: number) {
- const wedgeAngle = (2 * Math.PI) / numWedges;
- const startAngle = wedgeIdx * wedgeAngle - Math.PI / 2;
- const x1 = R * Math.cos(startAngle);
- const y1 = R * Math.sin(startAngle);
- const x2 = R * Math.cos(startAngle + wedgeAngle);
- const y2 = R * Math.sin(startAngle + wedgeAngle);
-
- return `M0,0 L${x1},${y1} A${R},${R} 0 0,1 ${x2},${y2} z`;
-}
diff --git a/src/clocks/css/clocks.css b/src/clocks/css/clocks.css
index e48dba72..b6b26bc8 100644
--- a/src/clocks/css/clocks.css
+++ b/src/clocks/css/clocks.css
@@ -1,6 +1,60 @@
.block-language-iron-vault-clock {
container: iron-vault-clock / inline-size;
}
+.iron-vault-clock-widget {
+ & .clock-segment {
+ vector-effect: non-scaling-stroke;
+ }
+ max-width: 200px;
+ @container iron-vault-clock (min-width: 300px) {
+ max-width: 300px;
+ }
+ pointer-events: none;
+ fill: var(--interactive-accent);
+ fill-opacity: 0.8;
+ stroke: var(--background-modifier-border);
+ stroke-width: 4;
+ aspect-ratio: 1;
+
+ &:hover {
+ fill-opacity: 0.8;
+
+ & .clock-segment {
+ &:hover {
+ fill: var(--interactive-accent-hover);
+ & ~ .clock-segment {
+ fill: var(--interactive-normal);
+ }
+ }
+ }
+ }
+
+ &:not(:hover) {
+ & .clock-segment {
+ &[aria-selected="true"] {
+ & ~ .clock-segment {
+ fill: var(--interactive-normal);
+ }
+ }
+ }
+ }
+
+ &[aria-valuenow="0"]:not(:hover) {
+ & .clock-segment {
+ fill: var(--interactive-normal);
+ }
+ }
+
+ & .clock-segment {
+ transition: fill 0.3s ease;
+ cursor: pointer;
+ pointer-events: visible;
+
+ &:active {
+ fill-opacity: 1;
+ }
+ }
+}
.iron-vault-clock {
margin: 0.5em auto;
& > .clock-name {
@@ -29,58 +83,5 @@
gap: 0.4em;
}
}
- & .clock-widget {
- & .clock-segment {
- vector-effect: non-scaling-stroke;
- }
- max-width: 200px;
- @container iron-vault-clock (min-width: 300px) {
- max-width: 300px;
- }
- pointer-events: none;
- fill: var(--interactive-accent);
- fill-opacity: 0.8;
- stroke: var(--background-modifier-border);
- stroke-width: 4;
- aspect-ratio: 1;
- &:hover {
- fill-opacity: 0.8;
-
- & .clock-segment {
- &:hover {
- fill: var(--interactive-accent-hover);
- & ~ .clock-segment {
- fill: var(--interactive-normal);
- }
- }
- }
- }
-
- &:not(:hover) {
- & .clock-segment {
- &[aria-selected="true"] {
- & ~ .clock-segment {
- fill: var(--interactive-normal);
- }
- }
- }
- }
-
- &[aria-valuenow="0"]:not(:hover) {
- & .clock-segment {
- fill: var(--interactive-normal);
- }
- }
-
- & .clock-segment {
- transition: fill 0.3s ease;
- cursor: pointer;
- pointer-events: visible;
-
- &:active {
- fill-opacity: 1;
- }
- }
- }
}
diff --git a/src/clocks/ui/clock-widget.ts b/src/clocks/ui/clock-widget.ts
new file mode 100644
index 00000000..0a4637a4
--- /dev/null
+++ b/src/clocks/ui/clock-widget.ts
@@ -0,0 +1,43 @@
+import { Clock } from "clocks/clock";
+import { html, svg } from "lit-html";
+import { map } from "lit-html/directives/map.js";
+import { range } from "lit-html/directives/range.js";
+
+export function clockWidget(
+ clock: Clock,
+ onClickSegment?: (newProgress: number, segment: number) => void,
+) {
+ const renderPath = (i: number) => {
+ return svg` onClickSegment(i === 0 && clock.progress === 1 ? 0 : i + 1, i))}
+ >`;
+ };
+
+ //() => this.updateClockProgress({ progress: i === 0 && clock.progress === 1 ? 0 : i + 1 })
+ return html``;
+}
+
+const R = 50;
+
+function pathString(wedgeIdx: number, numWedges: number) {
+ const wedgeAngle = (2 * Math.PI) / numWedges;
+ const startAngle = wedgeIdx * wedgeAngle - Math.PI / 2;
+ const x1 = R * Math.cos(startAngle);
+ const y1 = R * Math.sin(startAngle);
+ const x2 = R * Math.cos(startAngle + wedgeAngle);
+ const y2 = R * Math.sin(startAngle + wedgeAngle);
+
+ return `M0,0 L${x1},${y1} A${R},${R} 0 0,1 ${x2},${y2} z`;
+}