From 2768e36ebda51464247ad0c5f28c6624f0be5d1d Mon Sep 17 00:00:00 2001 From: Alex Date: Fri, 28 Jun 2024 09:19:28 +0800 Subject: [PATCH] Fixes --- eslint.config.mjs | 9 ++++++ src/main.ts | 5 +--- src/settings/index.ts | 33 +++++++++++++++++++- src/utils/helpers.ts | 29 ++++++++++++++---- src/view/dice.ts | 70 ++++++++++++++++++++++++++++++++++++------- src/view/index.ts | 2 +- 6 files changed, 126 insertions(+), 22 deletions(-) diff --git a/eslint.config.mjs b/eslint.config.mjs index bce2436..5ae0606 100644 --- a/eslint.config.mjs +++ b/eslint.config.mjs @@ -12,6 +12,15 @@ export default [ rules: { "@typescript-eslint/no-explicit-any": "off", "no-constant-condition": "off", + "no-unused-vars": "off", + "@typescript-eslint/no-unused-vars": [ + "warn", + { + argsIgnorePattern: "^_", + varsIgnorePattern: "^_", + caughtErrorsIgnorePattern: "^_", + }, + ], }, }, ]; diff --git a/src/main.ts b/src/main.ts index 93772e6..950ff57 100644 --- a/src/main.ts +++ b/src/main.ts @@ -64,10 +64,7 @@ export default class SoloToolkitPlugin extends Plugin { } async saveSetting(setting: Partial) { - this.settings = { - ...this.settings, - ...setting, - }; + Object.assign(this.settings, setting); return this.saveSettings(); } diff --git a/src/settings/index.ts b/src/settings/index.ts index 22a99c7..85eabac 100644 --- a/src/settings/index.ts +++ b/src/settings/index.ts @@ -3,6 +3,15 @@ import SoloToolkitPlugin from "../main"; export type ViewType = "dice" | "deck" | "oracle" | "word"; type DeckClipboardMode = "" | "md" | "path" | "png"; +type DiceClipboardMode = + | "plain" + | "parenthesis" + | "square" + | "curly" + | "code" + | "code+parenthesis" + | "code+square" + | "code+curly"; export interface SoloToolkitSettings { defaultView: ViewType; @@ -13,6 +22,7 @@ export interface SoloToolkitSettings { deckTarot: boolean; // obsolete deckClipboard: boolean; // obsolete deckClipboardMode: DeckClipboardMode; + diceClipboardMode: DiceClipboardMode; inlineCounters: boolean; oracleLanguage: string; @@ -31,6 +41,7 @@ export const DEFAULT_SETTINGS: SoloToolkitSettings = { deckTarot: true, deckClipboard: false, deckClipboardMode: "md", + diceClipboardMode: "code", inlineCounters: false, oracleLanguage: "en", @@ -120,9 +131,29 @@ export class SoloToolkitSettingTab extends PluginSettingTab { }) ); + new Setting(containerEl) + .setName("Dice click behavior") + .setDesc("What will be copied when you click on a dice roll result") + .addDropdown((dropdown) => { + dropdown + .addOption("plain", "d6: 4") + .addOption("parenthesis", "(d6: 4)") + .addOption("square", "[d6: 4]") + .addOption("curly", "{d6: 4}") + .addOption("code", "`d6: 4`") + .addOption("code+parenthesis", "`(d6: 4)`") + .addOption("code+square", "`[d6: 4]`") + .addOption("code+curly", "`{d6: 4}`"); + dropdown.setValue(this.plugin.settings.diceClipboardMode || ""); + dropdown.onChange(async (value: DiceClipboardMode) => { + this.plugin.settings.diceClipboardMode = value; + await this.plugin.saveSettings(); + }); + }); + new Setting(containerEl) .setName("Card click behavior") - .setDesc("Determines what happens when you click on a drawn card") + .setDesc("What will be copied when you click on a drawn card") .addDropdown((dropdown) => { dropdown .addOption("", "Off") diff --git a/src/utils/helpers.ts b/src/utils/helpers.ts index a2ad687..63f4f4c 100644 --- a/src/utils/helpers.ts +++ b/src/utils/helpers.ts @@ -29,6 +29,9 @@ export const trim = (value: string): string => value.trim(); export const identity = (value: string): string => value; +export const sum = (values: number[]): number => + values.reduce((sum, value) => sum + (value || 0), 0); + export const shuffle = (arr: T[]) => { let index = arr.length; let random = 0; @@ -40,6 +43,14 @@ export const shuffle = (arr: T[]) => { } }; +export function first(arr: T[]): T { + return arr[0]; +} + +export function last(arr: T[]): T { + return arr[arr.length - 1]; +} + export const clickToCopy = (value: string) => (event: MouseEvent) => { event.preventDefault(); navigator.clipboard.writeText(value); @@ -108,10 +119,16 @@ export const clickToCopyImage = img.src = value; }; -export function first(arr: T[]): T { - return arr[0]; -} - -export function last(arr: T[]): T { - return arr[arr.length - 1]; +export function bounce(timeout: number, once = false) { + let lastTime = 0; + return { + set: () => { + lastTime = Date.now(); + }, + check: () => { + const result = lastTime + timeout > Date.now(); + if (once) lastTime = 0; + return result; + }, + }; } diff --git a/src/view/dice.ts b/src/view/dice.ts index ae70ef0..c9be407 100644 --- a/src/view/dice.ts +++ b/src/view/dice.ts @@ -1,6 +1,6 @@ import { ExtraButtonComponent, setTooltip } from "obsidian"; import { SoloToolkitView as View } from "./index"; -import { clickToCopy, roll, rollIntervals } from "../utils"; +import { clickToCopy, roll, rollIntervals, bounce, sum, first } from "../utils"; const MAX_REMEMBER_SIZE = 100; @@ -57,25 +57,41 @@ export class DiceView { if (rollIntervals[i]) { setTimeout(reroll, rollIntervals[i]); } else { - const size = this.rolls[max].length; - const sum = this.rolls[max].reduce( - (result, value) => result + (value[0] || 0), - 0 - ); + // To prevent double-tap bug on mobile + const preventClick = bounce(1000, true); + el.onclick = (event) => { + if (preventClick.check()) return; const { shiftKey, ctrlKey, metaKey, altKey } = event; const anyKey = shiftKey || ctrlKey || metaKey || altKey; + + const [single, total] = this.formatForClipboard(value, max); + if (anyKey) { - clickToCopy(`[${size}d${max}: ${sum}]`)(event); + clickToCopy(total)(event); } else { - clickToCopy(`[d${max}: ${value}]`)(event); + clickToCopy(single)(event); } }; + el.oncontextmenu = (event) => { event.preventDefault(); - clickToCopy(`[${size}d${max}: ${sum}]`)(event); + event.stopPropagation(); + const [_single, total] = this.formatForClipboard(value, max); + clickToCopy(total)(event); + preventClick.set(); }; - setTooltip(container, `Total: ${sum}`); + + setTooltip( + container, + `${this.rolls[max].length}d${max}: ${sum( + this.rolls[max].map(first) + )}`, + { + delay: 0, + placement: "right", + } + ); } } }; @@ -87,6 +103,33 @@ export class DiceView { el.setText(value.toString()); } + formatForClipboard(value: number, max: number): [string, string] { + const size = this.rolls[max].length; + const total = sum(this.rolls[max].map(first)); + const singleStr = `d${max}: ${value}`; + const totalStr = `${size}d${max}: ${total}`; + switch (this.view.settings.diceClipboardMode) { + case "plain": + return [singleStr, totalStr]; + case "parenthesis": + return [`(${singleStr})`, `(${totalStr})`]; + case "square": + return [`[${singleStr}]`, `[${totalStr}]`]; + case "curly": + return [`{${singleStr}}`, `{${totalStr}}`]; + case "code": + return [`\`${singleStr}\``, `\`${totalStr}\``]; + case "code+parenthesis": + return [`\`(${singleStr})\``, `\`(${totalStr})\``]; + case "code+square": + return [`\`[${singleStr}]\``, `\`[${totalStr}]\``]; + case "code+curly": + return [`\`{${singleStr}}\``, `\`{${totalStr}}\``]; + default: + return [singleStr, totalStr]; + } + } + createDiceBtn(d: number) { const container = this.btnsEl.createDiv(`dice-variant dice-variant-${d}`); @@ -97,16 +140,23 @@ export class DiceView { .setIcon(`srt-d${d}`) .setTooltip(`Roll d${d}`); + // To prevent double-tap bug on mobile + const preventClick = bounce(1000, true); + btnEl.extraSettingsEl.onclick = (event) => { + if (preventClick.check()) return; const { shiftKey, ctrlKey, metaKey, altKey } = event; const a = shiftKey ? 0b001 : 0; const b = ctrlKey || metaKey ? 0b010 : 0; const c = altKey ? 0b100 : 0; this.addResult(resultsEl, d, a + b + c); }; + btnEl.extraSettingsEl.oncontextmenu = (event) => { event.preventDefault(); + event.stopPropagation(); this.addResult(resultsEl, d, 1); + preventClick.set(); }; } diff --git a/src/view/index.ts b/src/view/index.ts index 9eaf249..e52e755 100644 --- a/src/view/index.ts +++ b/src/view/index.ts @@ -46,7 +46,7 @@ export class SoloToolkitView extends ItemView { super(leaf); this.settings = settings; this.setSettings = setSettings; - this.tab = settings.defaultView || "deck"; + this.tab = this.settings.defaultView || "deck"; this.dice = new DiceView(this); this.deck = new DeckView(this); this.word = new WordView(this);