Skip to content

Commit

Permalink
feat: You can now create custom encounter builder headers
Browse files Browse the repository at this point in the history
  • Loading branch information
valentine195 committed May 2, 2023
1 parent 921034a commit 2c42744
Show file tree
Hide file tree
Showing 17 changed files with 1,353 additions and 189 deletions.
16 changes: 16 additions & 0 deletions index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -130,6 +130,7 @@ interface BuilderState {
sidebarIcon: boolean;
showXP: boolean;
showParty: boolean;
headers?: TableHeaderState[];
}

export interface InitiativeViewState {
Expand Down Expand Up @@ -185,6 +186,8 @@ export interface SRDMonster {
source?: string | string[];
friendly?: boolean;
hidden?: boolean;

[key: string]: any;
}

export interface HomebrewCreature {
Expand Down Expand Up @@ -284,3 +287,16 @@ export declare class Creature {
toJSON(): CreatureState;
static fromJSON(state: CreatureState): Creature;
}

//Builder
export enum SortFunctions {
LOCAL_COMPARE,
CONVERT_FRACTION,
CUSTOM
}
export type TableHeaderState = {
text: string;
field: string;
type: SortFunctions;
func?: string;
};
325 changes: 272 additions & 53 deletions package-lock.json

Large diffs are not rendered by default.

7 changes: 6 additions & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,10 @@
"author": "",
"license": "MIT",
"devDependencies": {
"@codemirror/commands": "^6.2.3",
"@codemirror/lang-javascript": "^6.1.7",
"@codemirror/language": "^6.6.0",
"@codemirror/search": "^6.4.0",
"@popperjs/core": "^2.11.7",
"@tsconfig/svelte": "^2.0.1",
"@types/jest": "^29.5.0",
Expand All @@ -30,8 +34,9 @@
"dotenv": "^10.0.0",
"esbuild": "^0.14.2",
"esbuild-svelte": "^0.6.0",
"fast-copy": "^3.0.1",
"jest": "^29.5.0",
"obsidian": "^0.16.3",
"obsidian": "^1.2.5",
"obsidian-overload": "^1.17.0",
"standard-version": "^9.3.2",
"svelte": "^3.49.0",
Expand Down
209 changes: 209 additions & 0 deletions src/builder/stores/table.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,209 @@
import { Updater, derived, get, writable } from "svelte/store";
import {
type SRDMonster,
SortFunctions,
type TableHeaderState
} from "../../../index";
import { convertFraction } from "../../utils";
import type InitiativeTracker from "../../main";
import { Modal } from "obsidian";
import copy from "fast-copy";
import Headers from "./table/Headers.svelte";
import { getId } from "src/utils/creature";

export const playerCount = writable(0);

export class TableHeader {
public active: boolean;
id = getId();
constructor(
public text: string,
public field: string,
public type: SortFunctions,
public func?: string
) {}
private _func: (a: SRDMonster, b: SRDMonster) => number =
this.getSortByType();
private getSortByType() {
switch (this.type) {
case SortFunctions.LOCAL_COMPARE: {
return (a: Record<string, any>, b: Record<string, any>) =>
(a[this.field] ?? "").localeCompare(b[this.field] ?? "");
}
case SortFunctions.CONVERT_FRACTION: {
return (a: Record<string, any>, b: Record<string, any>) =>
convertFraction(a[this.field] ?? 0) -
convertFraction(b[this.field] ?? 0);
}
case SortFunctions.CUSTOM: {
return new Function("a", "b", this.func) as (
a: SRDMonster,
b: SRDMonster
) => number;
}
}
}

public sortAsc(a: SRDMonster, b: SRDMonster) {
console.log(this._func(a, b));
return this._func(a, b);
}
public sortDesc(a: SRDMonster, b: SRDMonster) {
console.log(this._func(b, a));
return this._func(b, a);
}

public toState(): TableHeaderState {
return {
text: this.text,
field: this.field,
type: this.type,
...(this.func && this.func.length ? { func: this.func } : {})
};
}

public static fromState(state: TableHeaderState): TableHeader {
return new TableHeader(state.text, state.field, state.type, state.func);
}
public static get defaultState() {
return {
text: "",
field: "",
type: SortFunctions.LOCAL_COMPARE
};
}
}

export const DEFAULT_HEADERS: TableHeaderState[] = [
{
text: "CR",
field: "cr",
type: SortFunctions.CONVERT_FRACTION
},
{
text: "Type",
field: "type",
type: SortFunctions.LOCAL_COMPARE
},
{
text: "Size",
field: "size",
type: SortFunctions.LOCAL_COMPARE
},
{
text: "Alignment",
field: "alignment",
type: SortFunctions.LOCAL_COMPARE
}
];

export const NAME_HEADER = TableHeader.fromState({
text: "Name",
field: "name",
type: SortFunctions.LOCAL_COMPARE
});

export function createTable(plugin: InitiativeTracker, monsters: SRDMonster[]) {
if (!plugin.data.builder) {
plugin.data.builder = {
sidebarIcon: true,
showParty: true,
showXP: true
};
}
if (!plugin.data.builder.headers) {
plugin.data.builder.headers = copy(DEFAULT_HEADERS);
plugin.saveSettings();
}

const store = writable<TableHeader[]>(
plugin.data.builder.headers.map((h) => TableHeader.fromState(h))
);
const { subscribe, set, update } = store;
const creatures = writable<SRDMonster[]>(monsters);

let sortDir = writable(true); //true == asc, false == des
const allHeaders = derived(store, (headers) => {
return [NAME_HEADER, ...headers];
});
const sort = (field: TableHeader) =>
update((headers) => {
if (field.active) {
sortDir.update((v) => !v);
} else {
const curr = get(allHeaders).find((h) => h.active);
if (curr) curr.active = false;
field.active = true;
sortDir.set(true);
}

creatures.update((creatures) => {
creatures.sort(
get(sortDir)
? field.sortAsc.bind(field)
: field.sortDesc.bind(field)
);
return creatures;
});
return headers;
});
function updateAndSave(updater: Updater<TableHeader[]>): void {
update(updater);
plugin.saveSettings();
}
return {
allHeaders,
subscribe,
set,
update,
sort,
sortDir,
creatures,
setHeadersFromState: (headers: TableHeaderState[]) =>
updateAndSave((_) => {
plugin.data.builder.headers = headers;
const newHeaders = headers.map((h) => TableHeader.fromState(h));
const active = _.findIndex((h) => h.active);
if (active >= 0 && active < newHeaders.length) {
newHeaders[active].active = true;
}
return newHeaders;
}),
resetToDefault: () =>
updateAndSave((_) => {
plugin.data.builder.headers = copy(DEFAULT_HEADERS);
return plugin.data.builder.headers.map((h) =>
TableHeader.fromState(h)
);
})
};
}

export class SettingsModal extends Modal {
canceled: boolean = false;
reset = false;
constructor(public headers: TableHeaderState[]) {
super(app);
}
onOpen() {
this.titleEl.setText("Edit Headers");
const app = new Headers({
target: this.contentEl,
props: {
headers: copy(this.headers)
}
});
app.$on("update", (evt) => {
console.log("🚀 ~ file: table.ts:169 ~ evt:", evt);
this.headers = copy(evt.detail);
});
app.$on("cancel", () => {
this.canceled = true;
this.close();
});
app.$on("reset", () => {
this.reset = true;
this.close();
});
}
}
Loading

0 comments on commit 2c42744

Please sign in to comment.