Store default cards inside config folder for pasting into notes

This commit is contained in:
Alex 2024-07-03 11:18:50 +08:00
parent 9566e4916c
commit 5ea59eedc3
6 changed files with 121 additions and 36 deletions

File diff suppressed because one or more lines are too long

View file

@ -7,6 +7,9 @@ import {
} from "./settings";
import { SoloToolkitView, VIEW_TYPE } from "./view";
import { soloToolkitExtension } from "./extension";
import { exportDeck } from "./utils/deck";
import deckImages from "./icons/deck";
import tarotImages from "./icons/tarot";
export default class SoloToolkitPlugin extends Plugin {
settings: SoloToolkitSettings;
@ -15,6 +18,8 @@ export default class SoloToolkitPlugin extends Plugin {
await this.loadSettings();
registerIcons();
await exportDeck(this.app.vault, "standard", deckImages);
await exportDeck(this.app.vault, "tarot", tarotImages);
this.registerView(
VIEW_TYPE,

View file

@ -44,7 +44,7 @@ export class CustomDeck {
if (this.supportedExtensions.includes(child.extension)) {
this.deckCards.push(child);
} else if (child.extension === "md") {
this.vault.cachedRead(child).then((content: string) => {
this.vault.read(child).then((content: string) => {
if (!content) return;
const lines = content.split("\n").map(trim).filter(identity);
@ -67,9 +67,10 @@ export class CustomDeck {
});
}
}
if (child instanceof TFolder) {
this.parseFolder(child);
}
// NOTE: Commented out to skip nested folders
// if (child instanceof TFolder) {
// this.parseFolder(child);
// }
}
}
@ -92,7 +93,7 @@ export class CustomDeck {
} catch (error) {
return {
image: "",
flip: randomFrom(this.flip),
flip: 0,
};
}
}

View file

@ -1,4 +1,9 @@
import { TFile } from "obsidian";
import {
arrayBufferToBase64,
base64ToArrayBuffer,
TFile,
Vault,
} from "obsidian";
import { randomFrom } from "./dice";
import { shuffle } from "./helpers";
@ -6,41 +11,107 @@ export interface Card {
image: string;
flip?: number;
file?: TFile;
path?: string;
}
type Path = string;
const deckMemo: Record<string, string[]> = {};
export class DefaultDeck {
vault: Vault;
type: string;
cards: string[];
deckCards: string[];
excludedKeys: string[];
cards: Path[];
deckCards: Path[];
cardsLength: number = 0;
flip: number[] = [0, 2];
constructor(type: string, data: Record<string, string>) {
constructor(type: string, vault: Vault, excludedKeys: string[] = []) {
this.vault = vault;
this.type = type;
this.excludedKeys = excludedKeys;
this.cards = [];
this.deckCards = Object.values(data);
this.deckCards = [];
this.parseFolder();
this.shuffle();
}
update(data: Record<string, string>) {
this.deckCards = Object.values(data);
update(excludedKeys: string[] = []) {
this.excludedKeys = excludedKeys;
this.deckCards = [];
this.parseFolder();
}
parseFolder() {
const folderName = this.type.toLowerCase();
const folderPath =
this.vault.configDir + "/plugins/solo-rpg-toolkit/decks/" + folderName;
if (deckMemo[folderName]) {
for (const key of deckMemo[folderName]) {
if (this.excludedKeys.includes(key)) continue;
const fileName = `${key}.png`;
this.deckCards.push(folderPath + "/" + fileName);
}
}
}
async draw(): Promise<Card> {
if (!this.cards.length) this.shuffle();
const value = this.cards.pop() || "";
return {
image: "data:image/jpeg;base64," + value,
flip: randomFrom(this.flip),
};
const path = this.cards.pop() || "";
try {
if (!path) throw "No cards";
const bytes = await this.vault.adapter.readBinary(path);
const contentType = "image/png";
const image = `data:${contentType};base64,` + arrayBufferToBase64(bytes);
return {
image,
flip: randomFrom(this.flip),
path,
};
} catch (error) {
return {
image: "",
flip: 0,
};
}
}
shuffle() {
this.cards = [...this.deckCards];
shuffle(this.cards);
this.cardsLength = this.cards.length;
}
size(): [number, number] {
return [this.cards.length, this.deckCards.length];
return [this.cards.length, this.cardsLength];
}
}
export const exportDeck = async (
vault: Vault,
folderName: string,
data: Record<string, string>
) => {
const adapter = vault.adapter;
const basePath =
vault.configDir + "/plugins/solo-rpg-toolkit/decks/" + folderName;
try {
await adapter.mkdir(basePath);
await Promise.all(
Object.keys(data).map((key) => {
const filename = `${key}.png`;
return adapter.writeBinary(
basePath + "/" + filename,
base64ToArrayBuffer(data[key].trim())
);
})
);
deckMemo[folderName] = Object.keys(data);
} catch (error) {
// Failed to export deck images
}
};

View file

@ -3,8 +3,6 @@ import { SoloToolkitView as View } from "./index";
import { Card, DefaultDeck, clickToCopyImage, clickToCopy } from "../utils";
import { TabSelect } from "./shared/tabselect";
import { CustomDeck } from "src/utils/customdeck";
import deckImages, { jokerImages } from "../icons/deck";
import tarotImages from "../icons/tarot";
const MAX_REMEMBER_SIZE = 100;
@ -54,12 +52,10 @@ export class DeckView {
// Populate layout
this.createDefaultDeck(
"srt:Standard",
this.view.settings.deckJokers
? { ...deckImages, ...jokerImages }
: deckImages
"Standard",
this.view.settings.deckJokers ? [] : ["JokerBlack", "JokerRed"]
);
this.createDefaultDeck("srt:Tarot", tarotImages);
this.createDefaultDeck("Tarot", []);
if (this.view.settings.customDeckRoot) {
const folder = this.view.app.vault.getFolderByPath(
@ -107,7 +103,7 @@ export class DeckView {
}
addResult(card: DrawnCard, immediate = false) {
const { image, flip, file } = card;
const { image, flip, file, path } = card;
const parentElClass = ["deck-result", "image-result-content"];
if (flip) parentElClass.push(`deck-flip${flip}`);
@ -141,10 +137,22 @@ export class DeckView {
} else {
clickToCopy(`![[${file.path}]]`)(event);
}
} else if (path) {
const resourcePath =
this.view.app.vault.adapter.getResourcePath(path);
if (flip) {
clickToCopy(`![srt-flip${flip}](${resourcePath})`)(event);
} else {
clickToCopy(`![srt-flip0](${resourcePath})`)(event);
}
}
return;
case "path":
if (file) clickToCopy(file.path)(event);
if (file) {
clickToCopy(file.path)(event);
} else if (path) {
clickToCopy(path)(event);
}
return;
case "png":
clickToCopyImage(image, flip || 0)(event);
@ -165,16 +173,19 @@ export class DeckView {
}
}
createDefaultDeck(tabName: string, data: Record<string, string>) {
const label = tabName.replace("srt:", "");
createDefaultDeck(tabName: string, excludedKeys: string[]) {
this.tabContentEls[tabName] = this.tabContainerEl.createDiv("deck-buttons");
this.tabSelect.addOption(tabName, label);
this.tabSelect.addOption(tabName, tabName);
const deck = this.decks[tabName];
if (deck && deck instanceof DefaultDeck) {
deck.update(data);
deck.update(excludedKeys);
} else {
this.decks[tabName] = new DefaultDeck(tabName, data);
this.decks[tabName] = new DefaultDeck(
tabName,
this.view.app.vault,
excludedKeys
);
}
new ButtonComponent(this.tabContentEls[tabName])

View file

@ -219,7 +219,7 @@ export class WordView {
const templates: string[] = [];
const values: CustomTable = { [DEFAULT]: [] };
this.view.app.vault.cachedRead(file).then((content: string) => {
this.view.app.vault.read(file).then((content: string) => {
if (!content) return;
const lines = content.split("\n").map(trim).filter(identity);