From ae527dc54939c2d2ae88ecc0e76f835c9f4ef4be Mon Sep 17 00:00:00 2001 From: KyleKlus Date: Fri, 9 Feb 2024 18:31:14 +0100 Subject: [PATCH 01/37] UPDATE: Refactored each gui "view" into a separate file, so it is less cluttered and not a monolithic file --- src/gui/DecksListView.tsx | 170 ++++++++++++ src/gui/FlashcardReviewView.tsx | 371 ++++++++++++++++++++++++++ src/gui/flashcard-modal.tsx | 445 ++------------------------------ 3 files changed, 566 insertions(+), 420 deletions(-) create mode 100644 src/gui/DecksListView.tsx create mode 100644 src/gui/FlashcardReviewView.tsx diff --git a/src/gui/DecksListView.tsx b/src/gui/DecksListView.tsx new file mode 100644 index 00000000..41861d80 --- /dev/null +++ b/src/gui/DecksListView.tsx @@ -0,0 +1,170 @@ +import { Platform } from "obsidian"; +// eslint-disable-next-line @typescript-eslint/no-unused-vars +import h from "vhtml"; + +import type SRPlugin from "src/main"; +import { SRSettings } from "src/settings"; +import { COLLAPSE_ICON } from "src/constants"; +import { t } from "src/lang/helpers"; +import { Deck } from "../Deck"; +import { + DeckStats, + IFlashcardReviewSequencer as IFlashcardReviewSequencer, +} from "src/FlashcardReviewSequencer"; +import { TopicPath } from "src/TopicPath"; +import { FlashcardModalMode } from "./flashcard-modal"; + +export class DecksListView { + public plugin: SRPlugin; + public mode: FlashcardModalMode; + public titleEl: HTMLElement; + public contentEl: HTMLElement; + private reviewSequencer: IFlashcardReviewSequencer; + private settings: SRSettings; + private startReviewOfDeck: (deck: Deck) => void; + + constructor( + plugin: SRPlugin, + settings: SRSettings, + reviewSequencer: IFlashcardReviewSequencer, + titleEl: HTMLElement, + contentEl: HTMLElement, + startReviewOfDeck: (deck: Deck) => void + ) { + this.plugin = plugin; + this.settings = settings; + this.reviewSequencer = reviewSequencer; + + this.startReviewOfDeck = startReviewOfDeck; + + this.titleEl = titleEl; + this.contentEl = contentEl; + + this.titleEl.addClass("sr-centered"); + + this.contentEl.style.position = "relative"; + this.contentEl.style.height = "92%"; + this.contentEl.addClass("sr-modal-content"); + if (Platform.isMobile) { + this.contentEl.style.display = "block"; + } + } + /** + * Shows the DeckListView + */ + show(): void { + this.mode = FlashcardModalMode.DecksList; + + const stats: DeckStats = this.reviewSequencer.getDeckStats(TopicPath.emptyPath); + + this.titleEl.setText(t("DECKS")); + this.titleEl.innerHTML += ( +

+ + {stats.dueCount.toString()} + + + {stats.newCount.toString()} + + + {stats.totalCount.toString()} + +

+ ); + this.contentEl.empty(); + this.contentEl.setAttribute("id", "sr-flashcard-view"); + + for (const deck of this.reviewSequencer.originalDeckTree.subdecks) { + this.renderDeck(deck, this.contentEl); + } + } + + renderDeck(deck: Deck, containerEl: HTMLElement): void { + const deckView: HTMLElement = containerEl.createDiv("tree-item"); + + const deckViewSelf: HTMLElement = deckView.createDiv( + "tree-item-self tag-pane-tag is-clickable", + ); + const shouldBeInitiallyExpanded: boolean = this.settings.initiallyExpandAllSubdecksInTree; + let collapsed = !shouldBeInitiallyExpanded; + let collapseIconEl: HTMLElement | null = null; + if (deck.subdecks.length > 0) { + collapseIconEl = deckViewSelf.createDiv("tree-item-icon collapse-icon"); + collapseIconEl.innerHTML = COLLAPSE_ICON; + (collapseIconEl.childNodes[0] as HTMLElement).style.transform = collapsed + ? "rotate(-90deg)" + : ""; + } + + const deckViewInner: HTMLElement = deckViewSelf.createDiv("tree-item-inner"); + const deckViewInnerText: HTMLElement = deckViewInner.createDiv("tag-pane-tag-text"); + deckViewInnerText.innerHTML += {deck.deckName}; + const deckViewOuter: HTMLElement = deckViewSelf.createDiv("tree-item-flair-outer"); + const deckStats = this.reviewSequencer.getDeckStats(deck.getTopicPath()); + deckViewOuter.innerHTML += ( + + + {deckStats.dueCount.toString()} + + + {deckStats.newCount.toString()} + + + {deckStats.totalCount.toString()} + + + ); + + const deckViewChildren: HTMLElement = deckView.createDiv("tree-item-children"); + deckViewChildren.style.display = collapsed ? "none" : "block"; + if (deck.subdecks.length > 0) { + collapseIconEl.addEventListener("click", (e) => { + if (collapsed) { + (collapseIconEl.childNodes[0] as HTMLElement).style.transform = ""; + deckViewChildren.style.display = "block"; + } else { + (collapseIconEl.childNodes[0] as HTMLElement).style.transform = + "rotate(-90deg)"; + deckViewChildren.style.display = "none"; + } + + // We stop the propagation of the event so that the click event for deckViewSelf doesn't get called + // if the user clicks on the collapse icon + e.stopPropagation(); + collapsed = !collapsed; + }); + } + + // Add the click handler to deckViewSelf instead of deckViewInner so that it activates + // over the entire rectangle of the tree item, not just the text of the topic name + // https://github.com/st3v3nmw/obsidian-spaced-repetition/issues/709 + deckViewSelf.addEventListener("click", () => { + this.startReviewOfDeck(deck); + }); + + for (const subdeck of deck.subdecks) { + this.renderDeck(subdeck, deckViewChildren); + } + } +} diff --git a/src/gui/FlashcardReviewView.tsx b/src/gui/FlashcardReviewView.tsx new file mode 100644 index 00000000..6877fffe --- /dev/null +++ b/src/gui/FlashcardReviewView.tsx @@ -0,0 +1,371 @@ +import { App, Notice, Platform, setIcon } from "obsidian"; +// eslint-disable-next-line @typescript-eslint/no-unused-vars + +import type SRPlugin from "src/main"; +import { SRSettings } from "src/settings"; +import { textInterval, ReviewResponse } from "src/scheduling"; +import { t } from "src/lang/helpers"; +import { Card } from "../Card"; +import { CardListType, Deck } from "../Deck"; +import { CardType, Question } from "../Question"; +import { + FlashcardReviewMode, + IFlashcardReviewSequencer as IFlashcardReviewSequencer, +} from "src/FlashcardReviewSequencer"; +import { Note } from "src/Note"; +import { RenderMarkdownWrapper } from "src/util/RenderMarkdownWrapper"; +import { CardScheduleInfo } from "src/CardSchedule"; +import { FlashcardModalMode } from "./flashcard-modal"; + +export class FlashcardReviewView { + public app: App; + public plugin: SRPlugin; + public answerBtn: HTMLElement; + public titleEl: HTMLElement; + public contentEl: HTMLElement; + public flashcardView: HTMLElement; + private flashCardMenu: HTMLDivElement; + public hardBtn: HTMLElement; + public goodBtn: HTMLElement; + public easyBtn: HTMLElement; + public nextBtn: HTMLElement; + public responseDiv: HTMLElement; + public resetButton: HTMLButtonElement; + public editButton: HTMLElement; + public contextView: HTMLElement; + public mode: FlashcardModalMode; + private reviewSequencer: IFlashcardReviewSequencer; + private settings: SRSettings; + private reviewMode: FlashcardReviewMode; + private backClickHandler: () => void; + private editClickHandler: () => void; + + private get currentCard(): Card { + return this.reviewSequencer.currentCard; + } + + private get currentQuestion(): Question { + return this.reviewSequencer.currentQuestion; + } + + private get currentNote(): Note { + return this.reviewSequencer.currentNote; + } + + constructor( + app: App, + plugin: SRPlugin, + settings: SRSettings, + reviewSequencer: IFlashcardReviewSequencer, + reviewMode: FlashcardReviewMode, + titleEl: HTMLElement, + contentEl: HTMLElement, + backClickHandler: () => void, + editClickHandler: () => void + ) { + this.app = app; + this.plugin = plugin; + this.settings = settings; + this.reviewSequencer = reviewSequencer; + this.reviewMode = reviewMode; + this.backClickHandler = backClickHandler; + this.editClickHandler = editClickHandler; + + this.titleEl = titleEl; + this.contentEl = contentEl; + + this.titleEl.addClass("sr-centered"); + + this.contentEl.style.position = "relative"; + this.contentEl.style.height = "92%"; + this.contentEl.addClass("sr-modal-content"); + if (Platform.isMobile) { + this.contentEl.style.display = "block"; + } + + // TODO: refactor into event handler? + document.body.onkeydown = (e) => { + // TODO: Please fix this. It's ugly. + // Checks if the input textbox is in focus before processing keyboard shortcuts. + if ( + document.activeElement.nodeName !== "TEXTAREA" && + this.mode !== FlashcardModalMode.DecksList + ) { + const consume = () => { + e.preventDefault(); + e.stopPropagation(); + }; + if (this.mode !== FlashcardModalMode.Closed && e.code === "KeyS") { + this.skipCurrentCard(); + consume(); + } else if ( + this.mode === FlashcardModalMode.Front && + (e.code === "Space" || e.code === "Enter" || e.code === "NumpadEnter") + ) { + this.showAnswer(); + consume(); + } else if (this.mode === FlashcardModalMode.Back) { + if (e.code === "Numpad1" || e.code === "Digit1") { + this.processReview(ReviewResponse.Hard); + consume(); + } else if (e.code === "Numpad2" || e.code === "Digit2" || e.code === "Space") { + this.processReview(ReviewResponse.Good); + consume(); + } else if (e.code === "Numpad3" || e.code === "Digit3") { + this.processReview(ReviewResponse.Easy); + consume(); + } else if (e.code === "Numpad0" || e.code === "Digit0") { + this.processReview(ReviewResponse.Reset); + consume(); + } + } + } + }; + } + + async showCurrentCard(): Promise { + this.setupView(); + + const deck: Deck = this.reviewSequencer.currentDeck; + + this.responseDiv.style.display = "none"; + this.resetButton.disabled = true; + this.titleEl.setText(`${deck.deckName}: ${deck.getCardCount(CardListType.All, true)}`); + + this.answerBtn.style.display = "initial"; + this.flashcardView.empty(); + this.mode = FlashcardModalMode.Front; + + const wrapper: RenderMarkdownWrapper = new RenderMarkdownWrapper( + this.app, + this.plugin, + this.currentNote.filePath, + ); + await wrapper.renderMarkdownWrapper(this.currentCard.front, this.flashcardView); + + if (this.reviewMode == FlashcardReviewMode.Cram) { + // Same for mobile/desktop + this.hardBtn.setText(`${this.settings.flashcardHardText}`); + this.easyBtn.setText(`${this.settings.flashcardEasyText}`); + } else { + this.setupEaseButton( + this.hardBtn, + this.settings.flashcardHardText, + ReviewResponse.Hard, + ); + this.setupEaseButton( + this.goodBtn, + this.settings.flashcardGoodText, + ReviewResponse.Good, + ); + this.setupEaseButton( + this.easyBtn, + this.settings.flashcardEasyText, + ReviewResponse.Easy, + ); + } + + if (this.settings.showContextInCards) + this.contextView.setText( + this.formatQuestionContextText(this.currentQuestion.questionContext), + ); + } + + createShowAnswerButton() { + this.answerBtn = this.contentEl.createDiv(); + this.answerBtn.setAttribute("id", "sr-show-answer"); + this.answerBtn.setText(t("SHOW_ANSWER")); + this.answerBtn.addEventListener("click", () => { + this.showAnswer(); + }); + } + + createResponseButtons() { + this.responseDiv = this.contentEl.createDiv("sr-flashcard-response"); + + this.hardBtn = document.createElement("button"); + this.hardBtn.setAttribute("id", "sr-hard-btn"); + this.hardBtn.setText(this.settings.flashcardHardText); + this.hardBtn.addEventListener("click", () => { + this.processReview(ReviewResponse.Hard); + }); + this.responseDiv.appendChild(this.hardBtn); + + this.goodBtn = document.createElement("button"); + this.goodBtn.setAttribute("id", "sr-good-btn"); + this.goodBtn.setText(this.settings.flashcardGoodText); + this.goodBtn.addEventListener("click", () => { + this.processReview(ReviewResponse.Good); + }); + this.responseDiv.appendChild(this.goodBtn); + + this.easyBtn = document.createElement("button"); + this.easyBtn.setAttribute("id", "sr-easy-btn"); + this.easyBtn.setText(this.settings.flashcardEasyText); + this.easyBtn.addEventListener("click", () => { + this.processReview(ReviewResponse.Easy); + }); + this.responseDiv.appendChild(this.easyBtn); + this.responseDiv.style.display = "none"; + } + + createSkipButton() { + const skipButton = this.flashCardMenu.createEl("button"); + skipButton.addClass("sr-flashcard-menu-item"); + setIcon(skipButton, "chevrons-right"); + skipButton.setAttribute("aria-label", t("SKIP")); + skipButton.addEventListener("click", () => { + this.skipCurrentCard(); + }); + } + + createCardInfoButton() { + const cardInfo = this.flashCardMenu.createEl("button"); + cardInfo.addClass("sr-flashcard-menu-item"); + setIcon(cardInfo, "info"); + cardInfo.setAttribute("aria-label", "View Card Info"); + cardInfo.addEventListener("click", async () => { + this.displayCurrentCardInfoNotice(); + }); + } + + displayCurrentCardInfoNotice() { + const schedule = this.currentCard.scheduleInfo; + const currentEaseStr = t("CURRENT_EASE_HELP_TEXT") + (schedule?.ease ?? t("NEW")); + const currentIntervalStr = + t("CURRENT_INTERVAL_HELP_TEXT") + textInterval(schedule?.interval, false); + const generatedFromStr = t("CARD_GENERATED_FROM", { + notePath: this.currentQuestion.note.filePath, + }); + new Notice(currentEaseStr + "\n" + currentIntervalStr + "\n" + generatedFromStr); + } + + createBackButton() { + const backButton = this.flashCardMenu.createEl("button"); + backButton.addClass("sr-flashcard-menu-item"); + setIcon(backButton, "arrow-left"); + backButton.setAttribute("aria-label", t("BACK")); + backButton.addEventListener("click", () => { + /* this.plugin.data.historyDeck = ""; */ + this.backClickHandler(); + }); + } + + createResetButton() { + this.resetButton = this.flashCardMenu.createEl("button"); + this.resetButton.addClass("sr-flashcard-menu-item"); + setIcon(this.resetButton, "refresh-cw"); + this.resetButton.setAttribute("aria-label", t("RESET_CARD_PROGRESS")); + this.resetButton.addEventListener("click", () => { + this.processReview(ReviewResponse.Reset); + }); + } + + createEditButton() { + this.editButton = this.flashCardMenu.createEl("button"); + this.editButton.addClass("sr-flashcard-menu-item"); + setIcon(this.editButton, "edit"); + this.editButton.setAttribute("aria-label", t("EDIT_CARD")); + this.editButton.addEventListener("click", async () => { + this.editClickHandler(); + }); + } + + private setupView(): void { + this.contentEl.empty(); + + this.flashCardMenu = this.contentEl.createDiv("sr-flashcard-menu"); + + this.createBackButton(); + this.createEditButton(); + this.createResetButton(); + this.createCardInfoButton(); + this.createSkipButton(); + + if (this.settings.showContextInCards) { + this.contextView = this.contentEl.createDiv(); + this.contextView.setAttribute("id", "sr-context"); + } + + this.flashcardView = this.contentEl.createDiv("div"); + this.flashcardView.setAttribute("id", "sr-flashcard-view"); + + this.createResponseButtons(); + + this.createShowAnswerButton(); + + if (this.reviewMode == FlashcardReviewMode.Cram) { + this.goodBtn.style.display = "none"; + + this.responseDiv.addClass("sr-ignorestats-response"); + this.easyBtn.addClass("sr-ignorestats-btn"); + this.hardBtn.addClass("sr-ignorestats-btn"); + } + } + + private showAnswer(): void { + this.mode = FlashcardModalMode.Back; + + this.answerBtn.style.display = "none"; + this.responseDiv.style.display = "grid"; + + if (this.currentCard.hasSchedule) { + this.resetButton.disabled = false; + } + + if (this.currentQuestion.questionType !== CardType.Cloze) { + const hr: HTMLElement = document.createElement("hr"); + hr.setAttribute("id", "sr-hr-card-divide"); + this.flashcardView.appendChild(hr); + } else { + this.flashcardView.empty(); + } + + const wrapper: RenderMarkdownWrapper = new RenderMarkdownWrapper( + this.app, + this.plugin, + this.currentNote.filePath, + ); + wrapper.renderMarkdownWrapper(this.currentCard.back, this.flashcardView); + } + + private async processReview(response: ReviewResponse): Promise { + await this.reviewSequencer.processReview(response); + // console.log(`processReview: ${response}: ${this.currentCard?.front ?? 'None'}`) + await this.handleNextCard(); + } + + private async skipCurrentCard(): Promise { + this.reviewSequencer.skipCurrentCard(); + // console.log(`skipCurrentCard: ${this.currentCard?.front ?? 'None'}`) + await this.handleNextCard(); + } + + private async handleNextCard(): Promise { + if (this.currentCard != null) await this.showCurrentCard(); + else this.backClickHandler(); + } + + private formatQuestionContextText(questionContext: string[]): string { + const result = `${this.currentNote.file.basename} > ${questionContext.join(" > ")}`; + return result; + } + + private setupEaseButton( + button: HTMLElement, + buttonName: string, + reviewResponse: ReviewResponse, + ) { + const schedule: CardScheduleInfo = this.reviewSequencer.determineCardSchedule( + reviewResponse, + this.currentCard, + ); + const interval: number = schedule.interval; + + if (Platform.isMobile) { + button.setText(textInterval(interval, true)); + } else { + button.setText(`${buttonName} - ${textInterval(interval, false)}`); + } + } +} diff --git a/src/gui/flashcard-modal.tsx b/src/gui/flashcard-modal.tsx index a574de4d..d53513ab 100644 --- a/src/gui/flashcard-modal.tsx +++ b/src/gui/flashcard-modal.tsx @@ -20,6 +20,8 @@ import { Note } from "src/Note"; import { RenderMarkdownWrapper } from "src/util/RenderMarkdownWrapper"; import { CardScheduleInfo } from "src/CardSchedule"; import { TopicPath } from "src/TopicPath"; +import { DecksListView } from "./DecksListView"; +import { FlashcardReviewView } from "./FlashcardReviewView"; export enum FlashcardModalMode { DecksList, @@ -46,18 +48,6 @@ export class FlashcardModal extends Modal { private settings: SRSettings; private reviewMode: FlashcardReviewMode; - private get currentCard(): Card { - return this.reviewSequencer.currentCard; - } - - private get currentQuestion(): Question { - return this.reviewSequencer.currentQuestion; - } - - private get currentNote(): Note { - return this.reviewSequencer.currentNote; - } - constructor( app: App, plugin: SRPlugin, @@ -72,321 +62,48 @@ export class FlashcardModal extends Modal { this.reviewSequencer = reviewSequencer; this.reviewMode = reviewMode; - this.titleEl.setText(t("DECKS")); - this.titleEl.addClass("sr-centered"); - - if (Platform.isMobile) { - this.contentEl.style.display = "block"; - } this.modalEl.style.height = this.settings.flashcardHeightPercentage + "%"; this.modalEl.style.width = this.settings.flashcardWidthPercentage + "%"; - - this.contentEl.style.position = "relative"; - this.contentEl.style.height = "92%"; - this.contentEl.addClass("sr-modal-content"); - - // TODO: refactor into event handler? - document.body.onkeydown = (e) => { - // TODO: Please fix this. It's ugly. - // Checks if the input textbox is in focus before processing keyboard shortcuts. - if ( - document.activeElement.nodeName !== "TEXTAREA" && - this.mode !== FlashcardModalMode.DecksList - ) { - const consume = () => { - e.preventDefault(); - e.stopPropagation(); - }; - if (this.mode !== FlashcardModalMode.Closed && e.code === "KeyS") { - this.skipCurrentCard(); - consume(); - } else if ( - this.mode === FlashcardModalMode.Front && - (e.code === "Space" || e.code === "Enter" || e.code === "NumpadEnter") - ) { - this.showAnswer(); - consume(); - } else if (this.mode === FlashcardModalMode.Back) { - if (e.code === "Numpad1" || e.code === "Digit1") { - this.processReview(ReviewResponse.Hard); - consume(); - } else if (e.code === "Numpad2" || e.code === "Digit2" || e.code === "Space") { - this.processReview(ReviewResponse.Good); - consume(); - } else if (e.code === "Numpad3" || e.code === "Digit3") { - this.processReview(ReviewResponse.Easy); - consume(); - } else if (e.code === "Numpad0" || e.code === "Digit0") { - this.processReview(ReviewResponse.Reset); - consume(); - } - } - } - }; } onOpen(): void { - this.renderDecksList(); + this.showDecksList(); } onClose(): void { this.mode = FlashcardModalMode.Closed; } - renderDecksList(): void { - this.mode = FlashcardModalMode.DecksList; - const stats: DeckStats = this.reviewSequencer.getDeckStats(TopicPath.emptyPath); - this.titleEl.setText(t("DECKS")); - this.titleEl.innerHTML += ( -

- - {stats.dueCount.toString()} - - - {stats.newCount.toString()} - - - {stats.totalCount.toString()} - -

- ); - this.contentEl.empty(); - this.contentEl.setAttribute("id", "sr-flashcard-view"); - - for (const deck of this.reviewSequencer.originalDeckTree.subdecks) { - this.renderDeck(deck, this.contentEl, this); - } - } - - renderDeck(deck: Deck, containerEl: HTMLElement, modal: FlashcardModal): void { - const deckView: HTMLElement = containerEl.createDiv("tree-item"); - - const deckViewSelf: HTMLElement = deckView.createDiv( - "tree-item-self tag-pane-tag is-clickable", - ); - const shouldBeInitiallyExpanded: boolean = modal.settings.initiallyExpandAllSubdecksInTree; - let collapsed = !shouldBeInitiallyExpanded; - let collapseIconEl: HTMLElement | null = null; - if (deck.subdecks.length > 0) { - collapseIconEl = deckViewSelf.createDiv("tree-item-icon collapse-icon"); - collapseIconEl.innerHTML = COLLAPSE_ICON; - (collapseIconEl.childNodes[0] as HTMLElement).style.transform = collapsed - ? "rotate(-90deg)" - : ""; - } - - const deckViewInner: HTMLElement = deckViewSelf.createDiv("tree-item-inner"); - const deckViewInnerText: HTMLElement = deckViewInner.createDiv("tag-pane-tag-text"); - deckViewInnerText.innerHTML += {deck.deckName}; - const deckViewOuter: HTMLElement = deckViewSelf.createDiv("tree-item-flair-outer"); - const deckStats = this.reviewSequencer.getDeckStats(deck.getTopicPath()); - deckViewOuter.innerHTML += ( - - - {deckStats.dueCount.toString()} - - - {deckStats.newCount.toString()} - - - {deckStats.totalCount.toString()} - - - ); - - const deckViewChildren: HTMLElement = deckView.createDiv("tree-item-children"); - deckViewChildren.style.display = collapsed ? "none" : "block"; - if (deck.subdecks.length > 0) { - collapseIconEl.addEventListener("click", (e) => { - if (collapsed) { - (collapseIconEl.childNodes[0] as HTMLElement).style.transform = ""; - deckViewChildren.style.display = "block"; - } else { - (collapseIconEl.childNodes[0] as HTMLElement).style.transform = - "rotate(-90deg)"; - deckViewChildren.style.display = "none"; - } - - // We stop the propagation of the event so that the click event for deckViewSelf doesn't get called - // if the user clicks on the collapse icon - e.stopPropagation(); - collapsed = !collapsed; - }); - } - - // Add the click handler to deckViewSelf instead of deckViewInner so that it activates - // over the entire rectangle of the tree item, not just the text of the topic name - // https://github.com/st3v3nmw/obsidian-spaced-repetition/issues/709 - deckViewSelf.addEventListener("click", () => { - this.startReviewOfDeck(deck); - }); - - for (const subdeck of deck.subdecks) { - this.renderDeck(subdeck, deckViewChildren, modal); - } + showDecksList(): void { + new DecksListView( + this.plugin, + this.settings, + this.reviewSequencer, + this.titleEl, + this.contentEl, + this.startReviewOfDeck.bind(this) + ).show(); } startReviewOfDeck(deck: Deck) { this.reviewSequencer.setCurrentDeck(deck.getTopicPath()); if (this.reviewSequencer.hasCurrentCard) { - this.setupCardsView(); - this.showCurrentCard(); - } else this.renderDecksList(); - } - - setupCardsView(): void { - this.contentEl.empty(); - - this.flashCardMenu = this.contentEl.createDiv("sr-flashcard-menu"); - - this.createBackButton(); - this.createEditButton(); - this.createResetButton(); - this.createCardInfoButton(); - this.createSkipButton(); - - if (this.settings.showContextInCards) { - this.contextView = this.contentEl.createDiv(); - this.contextView.setAttribute("id", "sr-context"); - } - - this.flashcardView = this.contentEl.createDiv("div"); - this.flashcardView.setAttribute("id", "sr-flashcard-view"); - - this.createResponseButtons(); - - this.createShowAnswerButton(); - - if (this.reviewMode == FlashcardReviewMode.Cram) { - this.goodBtn.style.display = "none"; - - this.responseDiv.addClass("sr-ignorestats-response"); - this.easyBtn.addClass("sr-ignorestats-btn"); - this.hardBtn.addClass("sr-ignorestats-btn"); + new FlashcardReviewView( + this.app, + this.plugin, + this.settings, + this.reviewSequencer, + this.reviewMode, + this.titleEl, + this.contentEl, + this.showDecksList.bind(this), + this.doEditQuestionText.bind(this) + ).showCurrentCard(); + } else { + this.showDecksList(); } } - createShowAnswerButton() { - this.answerBtn = this.contentEl.createDiv(); - this.answerBtn.setAttribute("id", "sr-show-answer"); - this.answerBtn.setText(t("SHOW_ANSWER")); - this.answerBtn.addEventListener("click", () => { - this.showAnswer(); - }); - } - - createResponseButtons() { - this.responseDiv = this.contentEl.createDiv("sr-flashcard-response"); - - this.hardBtn = document.createElement("button"); - this.hardBtn.setAttribute("id", "sr-hard-btn"); - this.hardBtn.setText(this.settings.flashcardHardText); - this.hardBtn.addEventListener("click", () => { - this.processReview(ReviewResponse.Hard); - }); - this.responseDiv.appendChild(this.hardBtn); - - this.goodBtn = document.createElement("button"); - this.goodBtn.setAttribute("id", "sr-good-btn"); - this.goodBtn.setText(this.settings.flashcardGoodText); - this.goodBtn.addEventListener("click", () => { - this.processReview(ReviewResponse.Good); - }); - this.responseDiv.appendChild(this.goodBtn); - - this.easyBtn = document.createElement("button"); - this.easyBtn.setAttribute("id", "sr-easy-btn"); - this.easyBtn.setText(this.settings.flashcardEasyText); - this.easyBtn.addEventListener("click", () => { - this.processReview(ReviewResponse.Easy); - }); - this.responseDiv.appendChild(this.easyBtn); - this.responseDiv.style.display = "none"; - } - - createSkipButton() { - const skipButton = this.flashCardMenu.createEl("button"); - skipButton.addClass("sr-flashcard-menu-item"); - setIcon(skipButton, "chevrons-right"); - skipButton.setAttribute("aria-label", t("SKIP")); - skipButton.addEventListener("click", () => { - this.skipCurrentCard(); - }); - } - - createCardInfoButton() { - const cardInfo = this.flashCardMenu.createEl("button"); - cardInfo.addClass("sr-flashcard-menu-item"); - setIcon(cardInfo, "info"); - cardInfo.setAttribute("aria-label", "View Card Info"); - cardInfo.addEventListener("click", async () => { - this.displayCurrentCardInfoNotice(); - }); - } - - displayCurrentCardInfoNotice() { - const schedule = this.currentCard.scheduleInfo; - const currentEaseStr = t("CURRENT_EASE_HELP_TEXT") + (schedule?.ease ?? t("NEW")); - const currentIntervalStr = - t("CURRENT_INTERVAL_HELP_TEXT") + textInterval(schedule?.interval, false); - const generatedFromStr = t("CARD_GENERATED_FROM", { - notePath: this.currentQuestion.note.filePath, - }); - new Notice(currentEaseStr + "\n" + currentIntervalStr + "\n" + generatedFromStr); - } - - createBackButton() { - const backButton = this.flashCardMenu.createEl("button"); - backButton.addClass("sr-flashcard-menu-item"); - setIcon(backButton, "arrow-left"); - backButton.setAttribute("aria-label", t("BACK")); - backButton.addEventListener("click", () => { - /* this.plugin.data.historyDeck = ""; */ - this.renderDecksList(); - }); - } - - createResetButton() { - this.resetButton = this.flashCardMenu.createEl("button"); - this.resetButton.addClass("sr-flashcard-menu-item"); - setIcon(this.resetButton, "refresh-cw"); - this.resetButton.setAttribute("aria-label", t("RESET_CARD_PROGRESS")); - this.resetButton.addEventListener("click", () => { - this.processReview(ReviewResponse.Reset); - }); - } - - createEditButton() { - this.editButton = this.flashCardMenu.createEl("button"); - this.editButton.addClass("sr-flashcard-menu-item"); - setIcon(this.editButton, "edit"); - this.editButton.setAttribute("aria-label", t("EDIT_CARD")); - this.editButton.addEventListener("click", async () => { - this.doEditQuestionText(); - }); - } - async doEditQuestionText(): Promise { const currentQ: Question = this.reviewSequencer.currentQuestion; @@ -400,116 +117,4 @@ export class FlashcardModal extends Modal { }) .catch((reason) => console.log(reason)); } - - private showAnswer(): void { - this.mode = FlashcardModalMode.Back; - - this.answerBtn.style.display = "none"; - this.responseDiv.style.display = "grid"; - - if (this.currentCard.hasSchedule) { - this.resetButton.disabled = false; - } - - if (this.currentQuestion.questionType !== CardType.Cloze) { - const hr: HTMLElement = document.createElement("hr"); - hr.setAttribute("id", "sr-hr-card-divide"); - this.flashcardView.appendChild(hr); - } else { - this.flashcardView.empty(); - } - - const wrapper: RenderMarkdownWrapper = new RenderMarkdownWrapper( - this.app, - this.plugin, - this.currentNote.filePath, - ); - wrapper.renderMarkdownWrapper(this.currentCard.back, this.flashcardView); - } - - private async processReview(response: ReviewResponse): Promise { - await this.reviewSequencer.processReview(response); - // console.log(`processReview: ${response}: ${this.currentCard?.front ?? 'None'}`) - await this.handleNextCard(); - } - - private async skipCurrentCard(): Promise { - this.reviewSequencer.skipCurrentCard(); - // console.log(`skipCurrentCard: ${this.currentCard?.front ?? 'None'}`) - await this.handleNextCard(); - } - - private async handleNextCard(): Promise { - if (this.currentCard != null) await this.showCurrentCard(); - else this.renderDecksList(); - } - - private async showCurrentCard(): Promise { - const deck: Deck = this.reviewSequencer.currentDeck; - - this.responseDiv.style.display = "none"; - this.resetButton.disabled = true; - this.titleEl.setText(`${deck.deckName}: ${deck.getCardCount(CardListType.All, true)}`); - - this.answerBtn.style.display = "initial"; - this.flashcardView.empty(); - this.mode = FlashcardModalMode.Front; - - const wrapper: RenderMarkdownWrapper = new RenderMarkdownWrapper( - this.app, - this.plugin, - this.currentNote.filePath, - ); - await wrapper.renderMarkdownWrapper(this.currentCard.front, this.flashcardView); - - if (this.reviewMode == FlashcardReviewMode.Cram) { - // Same for mobile/desktop - this.hardBtn.setText(`${this.settings.flashcardHardText}`); - this.easyBtn.setText(`${this.settings.flashcardEasyText}`); - } else { - this.setupEaseButton( - this.hardBtn, - this.settings.flashcardHardText, - ReviewResponse.Hard, - ); - this.setupEaseButton( - this.goodBtn, - this.settings.flashcardGoodText, - ReviewResponse.Good, - ); - this.setupEaseButton( - this.easyBtn, - this.settings.flashcardEasyText, - ReviewResponse.Easy, - ); - } - - if (this.settings.showContextInCards) - this.contextView.setText( - this.formatQuestionContextText(this.currentQuestion.questionContext), - ); - } - - private formatQuestionContextText(questionContext: string[]): string { - const result = `${this.currentNote.file.basename} > ${questionContext.join(" > ")}`; - return result; - } - - private setupEaseButton( - button: HTMLElement, - buttonName: string, - reviewResponse: ReviewResponse, - ) { - const schedule: CardScheduleInfo = this.reviewSequencer.determineCardSchedule( - reviewResponse, - this.currentCard, - ); - const interval: number = schedule.interval; - - if (Platform.isMobile) { - button.setText(textInterval(interval, true)); - } else { - button.setText(`${buttonName} - ${textInterval(interval, false)}`); - } - } } From ce4ed19cdb50996416bb95d4aa32701583c54e78 Mon Sep 17 00:00:00 2001 From: KyleKlus Date: Fri, 9 Feb 2024 18:53:20 +0100 Subject: [PATCH 02/37] FIX: Rewrote the keydown handler to make it a bit nicer --- src/gui/FlashcardReviewView.tsx | 95 +++++++++++++++++++++------------ 1 file changed, 60 insertions(+), 35 deletions(-) diff --git a/src/gui/FlashcardReviewView.tsx b/src/gui/FlashcardReviewView.tsx index 6877fffe..cc511229 100644 --- a/src/gui/FlashcardReviewView.tsx +++ b/src/gui/FlashcardReviewView.tsx @@ -83,44 +83,69 @@ export class FlashcardReviewView { this.contentEl.style.display = "block"; } - // TODO: refactor into event handler? - document.body.onkeydown = (e) => { - // TODO: Please fix this. It's ugly. - // Checks if the input textbox is in focus before processing keyboard shortcuts. - if ( - document.activeElement.nodeName !== "TEXTAREA" && - this.mode !== FlashcardModalMode.DecksList - ) { - const consume = () => { - e.preventDefault(); - e.stopPropagation(); - }; - if (this.mode !== FlashcardModalMode.Closed && e.code === "KeyS") { - this.skipCurrentCard(); - consume(); - } else if ( - this.mode === FlashcardModalMode.Front && - (e.code === "Space" || e.code === "Enter" || e.code === "NumpadEnter") - ) { + document.addEventListener("keydown", this.keydownHandler.bind(this)); + } + + keydownHandler(e: KeyboardEvent): void { + // Checks if the input textbox is in focus before processing keyboard shortcuts. + if ( + document.activeElement.nodeName === "TEXTAREA" || + this.mode === FlashcardModalMode.DecksList || + this.mode === FlashcardModalMode.Closed + ) { return; } + + const consumeKeyEvent = () => { + e.preventDefault(); + e.stopPropagation(); + }; + + switch (e.code) { + case "KeyS": + this.skipCurrentCard(); + consumeKeyEvent(); + break; + case "Space": + if (this.mode === FlashcardModalMode.Front) { this.showAnswer(); - consume(); + consumeKeyEvent(); } else if (this.mode === FlashcardModalMode.Back) { - if (e.code === "Numpad1" || e.code === "Digit1") { - this.processReview(ReviewResponse.Hard); - consume(); - } else if (e.code === "Numpad2" || e.code === "Digit2" || e.code === "Space") { - this.processReview(ReviewResponse.Good); - consume(); - } else if (e.code === "Numpad3" || e.code === "Digit3") { - this.processReview(ReviewResponse.Easy); - consume(); - } else if (e.code === "Numpad0" || e.code === "Digit0") { - this.processReview(ReviewResponse.Reset); - consume(); - } + this.processReview(ReviewResponse.Good); + consumeKeyEvent(); } - } - }; + break; + case "Enter": + case "NumpadEnter": + if (this.mode !== FlashcardModalMode.Front) break; + this.showAnswer(); + consumeKeyEvent(); + break; + case "Numpad1": + case "Digit1": + if (this.mode !== FlashcardModalMode.Back) break; + this.processReview(ReviewResponse.Hard); + consumeKeyEvent(); + break; + case "Numpad2": + case "Digit2": + if (this.mode !== FlashcardModalMode.Back) break; + this.processReview(ReviewResponse.Good); + consumeKeyEvent(); + break; + case "Numpad3": + case "Digit3": + if (this.mode !== FlashcardModalMode.Back) break; + this.processReview(ReviewResponse.Easy); + consumeKeyEvent(); + break; + case "Numpad0": + case "Digit0": + if (this.mode !== FlashcardModalMode.Back) break; + this.processReview(ReviewResponse.Reset); + consumeKeyEvent(); + break; + default: + break; + } } async showCurrentCard(): Promise { From 63fdb938883d09824318e4d788ccf64b349027db Mon Sep 17 00:00:00 2001 From: KyleKlus Date: Fri, 9 Feb 2024 18:57:15 +0100 Subject: [PATCH 03/37] UPDATE: formatted code --- src/gui/DecksListView.tsx | 2 +- src/gui/FlashcardReviewView.tsx | 6 ++++-- src/gui/flashcard-modal.tsx | 4 ++-- 3 files changed, 7 insertions(+), 5 deletions(-) diff --git a/src/gui/DecksListView.tsx b/src/gui/DecksListView.tsx index 41861d80..bf1a34dd 100644 --- a/src/gui/DecksListView.tsx +++ b/src/gui/DecksListView.tsx @@ -29,7 +29,7 @@ export class DecksListView { reviewSequencer: IFlashcardReviewSequencer, titleEl: HTMLElement, contentEl: HTMLElement, - startReviewOfDeck: (deck: Deck) => void + startReviewOfDeck: (deck: Deck) => void, ) { this.plugin = plugin; this.settings = settings; diff --git a/src/gui/FlashcardReviewView.tsx b/src/gui/FlashcardReviewView.tsx index cc511229..af1f9257 100644 --- a/src/gui/FlashcardReviewView.tsx +++ b/src/gui/FlashcardReviewView.tsx @@ -61,7 +61,7 @@ export class FlashcardReviewView { titleEl: HTMLElement, contentEl: HTMLElement, backClickHandler: () => void, - editClickHandler: () => void + editClickHandler: () => void, ) { this.app = app; this.plugin = plugin; @@ -92,7 +92,9 @@ export class FlashcardReviewView { document.activeElement.nodeName === "TEXTAREA" || this.mode === FlashcardModalMode.DecksList || this.mode === FlashcardModalMode.Closed - ) { return; } + ) { + return; + } const consumeKeyEvent = () => { e.preventDefault(); diff --git a/src/gui/flashcard-modal.tsx b/src/gui/flashcard-modal.tsx index d53513ab..3dd1ad74 100644 --- a/src/gui/flashcard-modal.tsx +++ b/src/gui/flashcard-modal.tsx @@ -81,7 +81,7 @@ export class FlashcardModal extends Modal { this.reviewSequencer, this.titleEl, this.contentEl, - this.startReviewOfDeck.bind(this) + this.startReviewOfDeck.bind(this), ).show(); } @@ -97,7 +97,7 @@ export class FlashcardModal extends Modal { this.titleEl, this.contentEl, this.showDecksList.bind(this), - this.doEditQuestionText.bind(this) + this.doEditQuestionText.bind(this), ).showCurrentCard(); } else { this.showDecksList(); From 7ab1605f6b8581ddac3fab86f93b6eddbbe24e5d Mon Sep 17 00:00:00 2001 From: KyleKlus Date: Fri, 9 Feb 2024 18:59:02 +0100 Subject: [PATCH 04/37] UPDATE: Documented changes --- docs/changelog.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/docs/changelog.md b/docs/changelog.md index 5b57e738..b555a1b2 100644 --- a/docs/changelog.md +++ b/docs/changelog.md @@ -17,6 +17,8 @@ Generated by [`auto-changelog`](https://github.com/CookPete/auto-changelog). - Improved how spacing between the buttons was done - Centered the button groups, which wheren't centered - Fixed a hack in the response of the cram card mode +- Refactored each view into it's own file, to reduce clutter and having a monolithic file +- Fixed keydown handler with a proper event handler and a switch #### [1.11.1](https://github.com/st3v3nmw/obsidian-spaced-repetition/compare/1.11.0...1.11.1) From fefcd9fd02b3e0c272d57a553f10adcceec4ae6e Mon Sep 17 00:00:00 2001 From: KyleKlus Date: Fri, 9 Feb 2024 20:40:14 +0100 Subject: [PATCH 05/37] FIX: Fixed a bug where the keydown handler didn't ignore a key if the back wasn't shown --- src/gui/FlashcardReviewView.tsx | 20 +++++++++++++++----- 1 file changed, 15 insertions(+), 5 deletions(-) diff --git a/src/gui/FlashcardReviewView.tsx b/src/gui/FlashcardReviewView.tsx index af1f9257..256b35b3 100644 --- a/src/gui/FlashcardReviewView.tsx +++ b/src/gui/FlashcardReviewView.tsx @@ -117,31 +117,41 @@ export class FlashcardReviewView { break; case "Enter": case "NumpadEnter": - if (this.mode !== FlashcardModalMode.Front) break; + if (this.mode !== FlashcardModalMode.Front) { + break; + } this.showAnswer(); consumeKeyEvent(); break; case "Numpad1": case "Digit1": - if (this.mode !== FlashcardModalMode.Back) break; + if (this.mode !== FlashcardModalMode.Back) { + break; + } this.processReview(ReviewResponse.Hard); consumeKeyEvent(); break; case "Numpad2": case "Digit2": - if (this.mode !== FlashcardModalMode.Back) break; + if (this.mode !== FlashcardModalMode.Back) { + break; + } this.processReview(ReviewResponse.Good); consumeKeyEvent(); break; case "Numpad3": case "Digit3": - if (this.mode !== FlashcardModalMode.Back) break; + if (this.mode !== FlashcardModalMode.Back) { + break; + } this.processReview(ReviewResponse.Easy); consumeKeyEvent(); break; case "Numpad0": case "Digit0": - if (this.mode !== FlashcardModalMode.Back) break; + if (this.mode !== FlashcardModalMode.Back) { + break; + } this.processReview(ReviewResponse.Reset); consumeKeyEvent(); break; From 5e18164d0ec7b54854c3a9a46c81b4757b893317 Mon Sep 17 00:00:00 2001 From: KyleKlus Date: Sun, 11 Feb 2024 13:24:54 +0100 Subject: [PATCH 06/37] UPDATE: Reimplemented the title in the decks list and implemented a way of showing/hiding without the need of rerendering everything --- src/gui/DecksListView.tsx | 114 ++++++++++++++++++++++-------------- src/gui/flashcard-modal.tsx | 6 +- styles.css | 76 +++++++++++++++++++++--- 3 files changed, 143 insertions(+), 53 deletions(-) diff --git a/src/gui/DecksListView.tsx b/src/gui/DecksListView.tsx index bf1a34dd..518d1fb0 100644 --- a/src/gui/DecksListView.tsx +++ b/src/gui/DecksListView.tsx @@ -17,8 +17,16 @@ import { FlashcardModalMode } from "./flashcard-modal"; export class DecksListView { public plugin: SRPlugin; public mode: FlashcardModalMode; - public titleEl: HTMLElement; - public contentEl: HTMLElement; + public modalContentEl: HTMLElement; + + public view: HTMLDivElement; + public header: HTMLDivElement; + public title: HTMLDivElement; + public stats: HTMLDivElement; + public content: HTMLDivElement; + public treeHeader: HTMLDivElement; + public treeContent: HTMLDivElement; + private reviewSequencer: IFlashcardReviewSequencer; private settings: SRSettings; private startReviewOfDeck: (deck: Deck) => void; @@ -27,71 +35,87 @@ export class DecksListView { plugin: SRPlugin, settings: SRSettings, reviewSequencer: IFlashcardReviewSequencer, - titleEl: HTMLElement, contentEl: HTMLElement, startReviewOfDeck: (deck: Deck) => void, ) { this.plugin = plugin; this.settings = settings; this.reviewSequencer = reviewSequencer; - + this.modalContentEl = contentEl; this.startReviewOfDeck = startReviewOfDeck; + this.init(); + } + + /** + * Initializes all elements in the DeckListView + */ + init(): void { + this.view = this.modalContentEl.createDiv(); + this.view.addClasses(["sr-deck-list-view", "sr-is-hidden"]); - this.titleEl = titleEl; - this.contentEl = contentEl; + this.header = this.view.createDiv(); + this.header.addClass("sr-deck-list-header"); + + this.title = this.header.createDiv(); + this.title.addClass("sr-deck-list-title"); + this.title.setText(t("DECKS")); + + this.stats = this.header.createDiv(); + this.stats.addClass("sr-deck-list-header-stats-container"); + this._createHeaderStats(); + + this.content = this.view.createDiv(); + this.content.addClass("sr-deck-list-content"); - this.titleEl.addClass("sr-centered"); - this.contentEl.style.position = "relative"; - this.contentEl.style.height = "92%"; - this.contentEl.addClass("sr-modal-content"); - if (Platform.isMobile) { - this.contentEl.style.display = "block"; - } } + /** * Shows the DeckListView */ show(): void { this.mode = FlashcardModalMode.DecksList; - const stats: DeckStats = this.reviewSequencer.getDeckStats(TopicPath.emptyPath); + // Redraw in case the stats have changed + this._createHeaderStats(); - this.titleEl.setText(t("DECKS")); - this.titleEl.innerHTML += ( -

- - {stats.dueCount.toString()} - - - {stats.newCount.toString()} - - - {stats.totalCount.toString()} - -

- ); - this.contentEl.empty(); - this.contentEl.setAttribute("id", "sr-flashcard-view"); + this.content.empty(); for (const deck of this.reviewSequencer.originalDeckTree.subdecks) { - this.renderDeck(deck, this.contentEl); + this._renderDeck(deck, this.content); } + + this.view.removeClass("sr-is-hidden"); + } + + /** + * Hides the DeckListView + */ + hide() { + this.view.addClass("sr-is-hidden"); + } + + private _createHeaderStats() { + const statistics: DeckStats = this.reviewSequencer.getDeckStats(TopicPath.emptyPath); + this.stats.empty(); + + this._createHeaderStatsContainer(t("TOTAL_CARDS"), statistics.totalCount, "sr-bg-red"); + this._createHeaderStatsContainer(t("NEW_CARDS"), statistics.newCount, "sr-bg-blue"); + this._createHeaderStatsContainer(t("DUE_CARDS"), statistics.dueCount, "sr-bg-green"); + } + + private _createHeaderStatsContainer(statsLable: string, statsNumber: number, statsClass: string): void { + const statsContainer = this.stats.createDiv(); + statsContainer.ariaLabel = statsLable; + statsContainer.addClasses(["tag-pane-tag-count", "tree-item-flair", "sr-deck-list-header-stats-count", statsClass]); + + const lable = statsContainer.createDiv(); + lable.setText(statsLable); + const number = statsContainer.createDiv(); + number.setText(statsNumber.toString()); } - renderDeck(deck: Deck, containerEl: HTMLElement): void { + private _renderDeck(deck: Deck, containerEl: HTMLElement): void { const deckView: HTMLElement = containerEl.createDiv("tree-item"); const deckViewSelf: HTMLElement = deckView.createDiv( @@ -164,7 +188,7 @@ export class DecksListView { }); for (const subdeck of deck.subdecks) { - this.renderDeck(subdeck, deckViewChildren); + this._renderDeck(subdeck, deckViewChildren); } } } diff --git a/src/gui/flashcard-modal.tsx b/src/gui/flashcard-modal.tsx index 3dd1ad74..9fd4ad8b 100644 --- a/src/gui/flashcard-modal.tsx +++ b/src/gui/flashcard-modal.tsx @@ -64,6 +64,11 @@ export class FlashcardModal extends Modal { this.modalEl.style.height = this.settings.flashcardHeightPercentage + "%"; this.modalEl.style.width = this.settings.flashcardWidthPercentage + "%"; + + this.contentEl.addClass("sr-modal-content"); + if (Platform.isMobile) { + this.contentEl.style.display = "block"; + } } onOpen(): void { @@ -79,7 +84,6 @@ export class FlashcardModal extends Modal { this.plugin, this.settings, this.reviewSequencer, - this.titleEl, this.contentEl, this.startReviewOfDeck.bind(this), ).show(); diff --git a/styles.css b/styles.css index 60c8ad51..7ae924cd 100644 --- a/styles.css +++ b/styles.css @@ -1,3 +1,71 @@ +.sr-modal-content { + position: relative; +} + +.sr-is-hidden { + display: none; +} + +.sr-bg-green { + background-color: #4caf50; +} + +.sr-bg-blue { + background-color: #2196f3; +} + +.sr-bg-red { + background-color: #ff7043; +} + +.sr-deck-list-view, +.sr-flashcard-view, +.sr-edit-view { + display: flex; + flex-direction: column; + gap: var(--size-4-4); + width: 100%; + height: 100%; +} + +.sr-deck-list-header { + display: flex; + flex-direction: column; + gap: 8px; + width: 100%; + justify-content: center; + align-items: center; +} + +.sr-deck-list-title { + font-size: var(--font-ui-large); + font-weight: var(--font-semibold); + text-align: left; + line-height: var(--line-height-tight); +} + +.sr-deck-list-header-stats-container { + display: flex; + gap: 8px; +} + +.sr-deck-list-header-stats-count { + display: flex; + color: #ffffff; + padding: 4px; +} + +.sr-deck-list-header-stats-count > *:first-child { + min-width: 10ch; + border-right: 1px solid #ffffff; +} + +.sr-deck-list-header-stats-count > *:last-child { + min-width: 5ch; + padding-left: 4px; + text-align: center; +} + .sr-flashcard-menu { width: 100%; display: flex; @@ -60,12 +128,6 @@ flex-direction: column; } -.sr-deck-counts { - color: #ffffff; - margin-left: 4px; - padding: 4px; -} - #sr-show-answer { height: 48px; line-height: 48px; @@ -152,4 +214,4 @@ #sr-easy-btn { width: 100px; } -} +} \ No newline at end of file From 7103830e1f8492c31a9af09736d3ff5d975bf173 Mon Sep 17 00:00:00 2001 From: KyleKlus Date: Sun, 11 Feb 2024 13:36:36 +0100 Subject: [PATCH 07/37] UPDATE: Updated class naming scheme --- src/gui/DecksListView.tsx | 16 ++++++---------- styles.css | 16 ++++++++-------- 2 files changed, 14 insertions(+), 18 deletions(-) diff --git a/src/gui/DecksListView.tsx b/src/gui/DecksListView.tsx index 518d1fb0..90e0cdf1 100644 --- a/src/gui/DecksListView.tsx +++ b/src/gui/DecksListView.tsx @@ -24,8 +24,6 @@ export class DecksListView { public title: HTMLDivElement; public stats: HTMLDivElement; public content: HTMLDivElement; - public treeHeader: HTMLDivElement; - public treeContent: HTMLDivElement; private reviewSequencer: IFlashcardReviewSequencer; private settings: SRSettings; @@ -51,23 +49,21 @@ export class DecksListView { */ init(): void { this.view = this.modalContentEl.createDiv(); - this.view.addClasses(["sr-deck-list-view", "sr-is-hidden"]); + this.view.addClasses(["sr-deck-list", "sr-is-hidden"]); this.header = this.view.createDiv(); - this.header.addClass("sr-deck-list-header"); + this.header.addClass("sr-header"); this.title = this.header.createDiv(); - this.title.addClass("sr-deck-list-title"); + this.title.addClass("sr-title"); this.title.setText(t("DECKS")); this.stats = this.header.createDiv(); - this.stats.addClass("sr-deck-list-header-stats-container"); + this.stats.addClass("sr-header-stats-container"); this._createHeaderStats(); this.content = this.view.createDiv(); - this.content.addClass("sr-deck-list-content"); - - + this.content.addClass("sr-content"); } /** @@ -107,7 +103,7 @@ export class DecksListView { private _createHeaderStatsContainer(statsLable: string, statsNumber: number, statsClass: string): void { const statsContainer = this.stats.createDiv(); statsContainer.ariaLabel = statsLable; - statsContainer.addClasses(["tag-pane-tag-count", "tree-item-flair", "sr-deck-list-header-stats-count", statsClass]); + statsContainer.addClasses(["tag-pane-tag-count", "tree-item-flair", "sr-header-stats-count", statsClass]); const lable = statsContainer.createDiv(); lable.setText(statsLable); diff --git a/styles.css b/styles.css index 7ae924cd..37764314 100644 --- a/styles.css +++ b/styles.css @@ -18,8 +18,8 @@ background-color: #ff7043; } -.sr-deck-list-view, -.sr-flashcard-view, +.sr-deck-list, +.sr-flashcard, .sr-edit-view { display: flex; flex-direction: column; @@ -28,7 +28,7 @@ height: 100%; } -.sr-deck-list-header { +.sr-deck-list .sr-header { display: flex; flex-direction: column; gap: 8px; @@ -37,30 +37,30 @@ align-items: center; } -.sr-deck-list-title { +.sr-deck-list .sr-title { font-size: var(--font-ui-large); font-weight: var(--font-semibold); text-align: left; line-height: var(--line-height-tight); } -.sr-deck-list-header-stats-container { +.sr-deck-list .sr-header-stats-container { display: flex; gap: 8px; } -.sr-deck-list-header-stats-count { +.sr-deck-list .sr-header-stats-count { display: flex; color: #ffffff; padding: 4px; } -.sr-deck-list-header-stats-count > *:first-child { +.sr-deck-list .sr-header-stats-count > *:first-child { min-width: 10ch; border-right: 1px solid #ffffff; } -.sr-deck-list-header-stats-count > *:last-child { +.sr-deck-list .sr-header-stats-count > *:last-child { min-width: 5ch; padding-left: 4px; text-align: center; From 14568d8eb7ac6dfafdfa9a5a44e4d297e3d11df0 Mon Sep 17 00:00:00 2001 From: KyleKlus Date: Sun, 11 Feb 2024 14:17:43 +0100 Subject: [PATCH 08/37] UPDATE: Changed the deck list header style a bit --- src/gui/DecksListView.tsx | 2 +- styles.css | 9 +++++---- 2 files changed, 6 insertions(+), 5 deletions(-) diff --git a/src/gui/DecksListView.tsx b/src/gui/DecksListView.tsx index 90e0cdf1..19569b3c 100644 --- a/src/gui/DecksListView.tsx +++ b/src/gui/DecksListView.tsx @@ -106,7 +106,7 @@ export class DecksListView { statsContainer.addClasses(["tag-pane-tag-count", "tree-item-flair", "sr-header-stats-count", statsClass]); const lable = statsContainer.createDiv(); - lable.setText(statsLable); + lable.setText(statsLable+":"); const number = statsContainer.createDiv(); number.setText(statsNumber.toString()); } diff --git a/styles.css b/styles.css index 37764314..169072af 100644 --- a/styles.css +++ b/styles.css @@ -32,9 +32,11 @@ display: flex; flex-direction: column; gap: 8px; + padding-bottom: 14px; width: 100%; justify-content: center; align-items: center; + border-bottom: 1px solid var(--hr-color); } .sr-deck-list .sr-title { @@ -53,17 +55,16 @@ display: flex; color: #ffffff; padding: 4px; + gap: 4px; } .sr-deck-list .sr-header-stats-count > *:first-child { min-width: 10ch; - border-right: 1px solid #ffffff; } .sr-deck-list .sr-header-stats-count > *:last-child { - min-width: 5ch; - padding-left: 4px; - text-align: center; + min-width: 3ch; + text-align: right; } .sr-flashcard-menu { From d21464ee9f70dc236d1f0500f3e02a22b48615ec Mon Sep 17 00:00:00 2001 From: KyleKlus Date: Sun, 11 Feb 2024 14:26:33 +0100 Subject: [PATCH 09/37] UPDATE: cleaned some old code --- src/gui/flashcard-modal.tsx | 15 --------------- 1 file changed, 15 deletions(-) diff --git a/src/gui/flashcard-modal.tsx b/src/gui/flashcard-modal.tsx index 9fd4ad8b..4e12ae71 100644 --- a/src/gui/flashcard-modal.tsx +++ b/src/gui/flashcard-modal.tsx @@ -16,10 +16,6 @@ import { IFlashcardReviewSequencer as IFlashcardReviewSequencer, } from "src/FlashcardReviewSequencer"; import { FlashcardEditModal } from "./flashcards-edit-modal"; -import { Note } from "src/Note"; -import { RenderMarkdownWrapper } from "src/util/RenderMarkdownWrapper"; -import { CardScheduleInfo } from "src/CardSchedule"; -import { TopicPath } from "src/TopicPath"; import { DecksListView } from "./DecksListView"; import { FlashcardReviewView } from "./FlashcardReviewView"; @@ -32,17 +28,6 @@ export enum FlashcardModalMode { export class FlashcardModal extends Modal { public plugin: SRPlugin; - public answerBtn: HTMLElement; - public flashcardView: HTMLElement; - private flashCardMenu: HTMLDivElement; - public hardBtn: HTMLElement; - public goodBtn: HTMLElement; - public easyBtn: HTMLElement; - public nextBtn: HTMLElement; - public responseDiv: HTMLElement; - public resetButton: HTMLButtonElement; - public editButton: HTMLElement; - public contextView: HTMLElement; public mode: FlashcardModalMode; private reviewSequencer: IFlashcardReviewSequencer; private settings: SRSettings; From 5a0c2612209b629fedfe5d8bf66c3e5e29b5fae5 Mon Sep 17 00:00:00 2001 From: KyleKlus Date: Sun, 11 Feb 2024 14:28:05 +0100 Subject: [PATCH 10/37] UPDATE: Another bit of code cleanup --- src/gui/flashcard-modal.tsx | 12 ++++-------- 1 file changed, 4 insertions(+), 8 deletions(-) diff --git a/src/gui/flashcard-modal.tsx b/src/gui/flashcard-modal.tsx index 4e12ae71..20b9b904 100644 --- a/src/gui/flashcard-modal.tsx +++ b/src/gui/flashcard-modal.tsx @@ -1,17 +1,13 @@ -import { Modal, App, Notice, Platform, setIcon } from "obsidian"; +import { Modal, App, Platform } from "obsidian"; // eslint-disable-next-line @typescript-eslint/no-unused-vars import h from "vhtml"; import type SRPlugin from "src/main"; import { SRSettings } from "src/settings"; -import { textInterval, ReviewResponse } from "src/scheduling"; -import { COLLAPSE_ICON } from "src/constants"; -import { t } from "src/lang/helpers"; -import { Card } from "../Card"; -import { CardListType, Deck } from "../Deck"; -import { CardType, Question } from "../Question"; + +import { Deck } from "../Deck"; +import { Question } from "../Question"; import { - DeckStats, FlashcardReviewMode, IFlashcardReviewSequencer as IFlashcardReviewSequencer, } from "src/FlashcardReviewSequencer"; From 4196d622b1939d4f27f855ce85c99085a87f47d7 Mon Sep 17 00:00:00 2001 From: KyleKlus Date: Sun, 11 Feb 2024 14:34:21 +0100 Subject: [PATCH 11/37] FIX: Fixed that the close button wasn't clickable --- src/gui/flashcard-modal.tsx | 1 + styles.css | 8 ++++++++ 2 files changed, 9 insertions(+) diff --git a/src/gui/flashcard-modal.tsx b/src/gui/flashcard-modal.tsx index 20b9b904..3f9fbb82 100644 --- a/src/gui/flashcard-modal.tsx +++ b/src/gui/flashcard-modal.tsx @@ -45,6 +45,7 @@ export class FlashcardModal extends Modal { this.modalEl.style.height = this.settings.flashcardHeightPercentage + "%"; this.modalEl.style.width = this.settings.flashcardWidthPercentage + "%"; + this.modalEl.addClass("sr-modal"); this.contentEl.addClass("sr-modal-content"); if (Platform.isMobile) { diff --git a/styles.css b/styles.css index 169072af..b13d8d4f 100644 --- a/styles.css +++ b/styles.css @@ -1,3 +1,11 @@ +.sr-modal .modal-close-button { + z-index: 21; +} + +body:not(.native-scrollbars) .sr-modal .modal-close-button { + top: 12px; +} + .sr-modal-content { position: relative; } From daa314310a7e5f7316646850b0691e46bb2cc9d7 Mon Sep 17 00:00:00 2001 From: KyleKlus Date: Sun, 11 Feb 2024 15:11:33 +0100 Subject: [PATCH 12/37] UPDATE: Redesigned DecksListView --- src/gui/DecksListView.tsx | 87 ++++++++++++++++++++----------------- src/gui/flashcard-modal.tsx | 22 +++++++--- styles.css | 19 ++++++++ 3 files changed, 80 insertions(+), 48 deletions(-) diff --git a/src/gui/DecksListView.tsx b/src/gui/DecksListView.tsx index 19569b3c..d09f6578 100644 --- a/src/gui/DecksListView.tsx +++ b/src/gui/DecksListView.tsx @@ -76,7 +76,6 @@ export class DecksListView { this._createHeaderStats(); this.content.empty(); - for (const deck of this.reviewSequencer.originalDeckTree.subdecks) { this._renderDeck(deck, this.content); } @@ -106,85 +105,91 @@ export class DecksListView { statsContainer.addClasses(["tag-pane-tag-count", "tree-item-flair", "sr-header-stats-count", statsClass]); const lable = statsContainer.createDiv(); - lable.setText(statsLable+":"); + lable.setText(statsLable + ":"); + const number = statsContainer.createDiv(); number.setText(statsNumber.toString()); } - private _renderDeck(deck: Deck, containerEl: HTMLElement): void { - const deckView: HTMLElement = containerEl.createDiv("tree-item"); - - const deckViewSelf: HTMLElement = deckView.createDiv( + private _renderDeck(deck: Deck, container: HTMLElement): void { + const deckTree: HTMLElement = container.createDiv("tree-item"); + const deckTreeSelf: HTMLElement = deckTree.createDiv( "tree-item-self tag-pane-tag is-clickable", ); + const shouldBeInitiallyExpanded: boolean = this.settings.initiallyExpandAllSubdecksInTree; let collapsed = !shouldBeInitiallyExpanded; let collapseIconEl: HTMLElement | null = null; if (deck.subdecks.length > 0) { - collapseIconEl = deckViewSelf.createDiv("tree-item-icon collapse-icon"); + collapseIconEl = deckTreeSelf.createDiv("tree-item-icon collapse-icon"); collapseIconEl.innerHTML = COLLAPSE_ICON; (collapseIconEl.childNodes[0] as HTMLElement).style.transform = collapsed ? "rotate(-90deg)" : ""; } - const deckViewInner: HTMLElement = deckViewSelf.createDiv("tree-item-inner"); - const deckViewInnerText: HTMLElement = deckViewInner.createDiv("tag-pane-tag-text"); - deckViewInnerText.innerHTML += {deck.deckName}; - const deckViewOuter: HTMLElement = deckViewSelf.createDiv("tree-item-flair-outer"); + const deckTreeInner: HTMLElement = deckTreeSelf.createDiv("tree-item-inner"); + const deckTreeInnerText: HTMLElement = deckTreeInner.createDiv("tag-pane-tag-text"); + deckTreeInnerText.innerHTML += {deck.deckName}; + + const deckTreeOuter: HTMLDivElement = deckTreeSelf.createDiv(); + deckTreeOuter.addClasses(["tree-item-flair-outer", "sr-tree-stats-container"]); + const deckStats = this.reviewSequencer.getDeckStats(deck.getTopicPath()); - deckViewOuter.innerHTML += ( - - - {deckStats.dueCount.toString()} - - - {deckStats.newCount.toString()} - - - {deckStats.totalCount.toString()} - - - ); + this._createStats(deckStats, deckTreeOuter); - const deckViewChildren: HTMLElement = deckView.createDiv("tree-item-children"); - deckViewChildren.style.display = collapsed ? "none" : "block"; + const deckTreeChildren: HTMLElement = deckTree.createDiv("tree-item-children"); + deckTreeChildren.style.display = collapsed ? "none" : "block"; if (deck.subdecks.length > 0) { collapseIconEl.addEventListener("click", (e) => { if (collapsed) { (collapseIconEl.childNodes[0] as HTMLElement).style.transform = ""; - deckViewChildren.style.display = "block"; + deckTreeChildren.style.display = "block"; } else { (collapseIconEl.childNodes[0] as HTMLElement).style.transform = "rotate(-90deg)"; - deckViewChildren.style.display = "none"; + deckTreeChildren.style.display = "none"; } - // We stop the propagation of the event so that the click event for deckViewSelf doesn't get called + // We stop the propagation of the event so that the click event for deckTreeSelf doesn't get called // if the user clicks on the collapse icon e.stopPropagation(); collapsed = !collapsed; }); } - // Add the click handler to deckViewSelf instead of deckViewInner so that it activates + // Add the click handler to deckTreeSelf instead of deckTreeInner so that it activates // over the entire rectangle of the tree item, not just the text of the topic name // https://github.com/st3v3nmw/obsidian-spaced-repetition/issues/709 - deckViewSelf.addEventListener("click", () => { + deckTreeSelf.addEventListener("click", () => { this.startReviewOfDeck(deck); }); for (const subdeck of deck.subdecks) { - this._renderDeck(subdeck, deckViewChildren); + this._renderDeck(subdeck, deckTreeChildren); } } + + private _createStats(statistics: DeckStats, statsWrapper: HTMLDivElement) { + statsWrapper.empty(); + + this._createStatsContainer(t("TOTAL_CARDS"), statistics.totalCount, "sr-bg-red", statsWrapper); + this._createStatsContainer(t("NEW_CARDS"), statistics.newCount, "sr-bg-blue", statsWrapper); + this._createStatsContainer(t("DUE_CARDS"), statistics.dueCount, "sr-bg-green", statsWrapper); + } + + private _createStatsContainer(statsLable: string, statsNumber: number, statsClass: string, statsWrapper: HTMLDivElement): void { + const statsContainer = statsWrapper.createDiv(); + + statsContainer.ariaLabel = statsLable; + + statsContainer.addClasses([ + "tag-pane-tag-count", + "tree-item-flair", + "sr-tree-stats-count", + statsClass + ]); + + statsContainer.setText(statsNumber.toString()); + } } diff --git a/src/gui/flashcard-modal.tsx b/src/gui/flashcard-modal.tsx index 3f9fbb82..787804a1 100644 --- a/src/gui/flashcard-modal.tsx +++ b/src/gui/flashcard-modal.tsx @@ -28,6 +28,7 @@ export class FlashcardModal extends Modal { private reviewSequencer: IFlashcardReviewSequencer; private settings: SRSettings; private reviewMode: FlashcardReviewMode; + private deckView: DecksListView; constructor( app: App, @@ -51,6 +52,14 @@ export class FlashcardModal extends Modal { if (Platform.isMobile) { this.contentEl.style.display = "block"; } + + this.deckView = new DecksListView( + this.plugin, + this.settings, + this.reviewSequencer, + this.contentEl, + this.startReviewOfDeck.bind(this), + ); } onOpen(): void { @@ -62,16 +71,15 @@ export class FlashcardModal extends Modal { } showDecksList(): void { - new DecksListView( - this.plugin, - this.settings, - this.reviewSequencer, - this.contentEl, - this.startReviewOfDeck.bind(this), - ).show(); + this.deckView.show(); + } + + hideDecksList(): void { + this.deckView.hide(); } startReviewOfDeck(deck: Deck) { + this.hideDecksList(); this.reviewSequencer.setCurrentDeck(deck.getTopicPath()); if (this.reviewSequencer.hasCurrentCard) { new FlashcardReviewView( diff --git a/styles.css b/styles.css index b13d8d4f..2d648192 100644 --- a/styles.css +++ b/styles.css @@ -14,6 +14,12 @@ body:not(.native-scrollbars) .sr-modal .modal-close-button { display: none; } +.sr-bg-blue, +.sr-bg-green, +.sr-bg-red { + color: #ffffff; +} + .sr-bg-green { background-color: #4caf50; } @@ -75,6 +81,19 @@ body:not(.native-scrollbars) .sr-modal .modal-close-button { text-align: right; } +.sr-deck-list .sr-tree-stats-container { + display: flex; + gap: 8px; +} + +.sr-deck-list .sr-tree-stats-count { + min-width: 3ch; + padding: 2px 4px; + box-sizing: content-box; + text-align: center; + color: #ffffff !important; +} + .sr-flashcard-menu { width: 100%; display: flex; From c79679525384e11f075876520cc6cdb03a693852 Mon Sep 17 00:00:00 2001 From: KyleKlus Date: Sun, 11 Feb 2024 16:13:51 +0100 Subject: [PATCH 13/37] UPDATE: Updated the DecksListView design --- src/gui/DecksListView.tsx | 11 +++++------ styles.css | 26 ++++++++++++++++++++++---- 2 files changed, 27 insertions(+), 10 deletions(-) diff --git a/src/gui/DecksListView.tsx b/src/gui/DecksListView.tsx index d09f6578..71ab313c 100644 --- a/src/gui/DecksListView.tsx +++ b/src/gui/DecksListView.tsx @@ -1,4 +1,3 @@ -import { Platform } from "obsidian"; // eslint-disable-next-line @typescript-eslint/no-unused-vars import h from "vhtml"; @@ -77,7 +76,7 @@ export class DecksListView { this.content.empty(); for (const deck of this.reviewSequencer.originalDeckTree.subdecks) { - this._renderDeck(deck, this.content); + this._createTree(deck, this.content); } this.view.removeClass("sr-is-hidden"); @@ -111,10 +110,10 @@ export class DecksListView { number.setText(statsNumber.toString()); } - private _renderDeck(deck: Deck, container: HTMLElement): void { - const deckTree: HTMLElement = container.createDiv("tree-item"); + private _createTree(deck: Deck, container: HTMLElement): void { + const deckTree: HTMLElement = container.createDiv("tree-item sr-tree-item-container"); const deckTreeSelf: HTMLElement = deckTree.createDiv( - "tree-item-self tag-pane-tag is-clickable", + "tree-item-self tag-pane-tag is-clickable sr-tree-item-row", ); const shouldBeInitiallyExpanded: boolean = this.settings.initiallyExpandAllSubdecksInTree; @@ -166,7 +165,7 @@ export class DecksListView { }); for (const subdeck of deck.subdecks) { - this._renderDeck(subdeck, deckTreeChildren); + this._createTree(subdeck, deckTreeChildren); } } diff --git a/styles.css b/styles.css index 2d648192..730a8777 100644 --- a/styles.css +++ b/styles.css @@ -25,7 +25,7 @@ body:not(.native-scrollbars) .sr-modal .modal-close-button { } .sr-bg-blue { - background-color: #2196f3; + background-color: #2094f3; } .sr-bg-red { @@ -37,7 +37,7 @@ body:not(.native-scrollbars) .sr-modal .modal-close-button { .sr-edit-view { display: flex; flex-direction: column; - gap: var(--size-4-4); + gap: 20px; width: 100%; height: 100%; } @@ -81,14 +81,32 @@ body:not(.native-scrollbars) .sr-modal .modal-close-button { text-align: right; } +.sr-deck-list .sr-tree-item-row { + padding-top: 2px; + padding-bottom: 2px; + margin-bottom: 0; +} + +.sr-deck-list .sr-tree-item-row:hover .sr-bg-green { + background-color: hsl(122, 39%, 44%); +} + +.sr-deck-list .sr-tree-item-row:hover .sr-bg-blue { + background-color: hsl(207, 90%, 49%); +} + +.sr-deck-list .sr-tree-item-row:hover .sr-bg-red { + background-color: hsl(14, 100%, 58%); +} + .sr-deck-list .sr-tree-stats-container { display: flex; - gap: 8px; + gap: 4px; } .sr-deck-list .sr-tree-stats-count { min-width: 3ch; - padding: 2px 4px; + padding: 4px; box-sizing: content-box; text-align: center; color: #ffffff !important; From bce8450856fc72cba4bc7e8b0481318afa9eed5d Mon Sep 17 00:00:00 2001 From: KyleKlus Date: Sun, 11 Feb 2024 19:03:10 +0100 Subject: [PATCH 14/37] UPDATE: Major reimplantation of the FlashcardsReviewView & again small changes to the DecksListView --- src/gui/DecksListView.tsx | 8 +- src/gui/FlashcardReviewView.tsx | 505 +++++++++++++++++--------------- src/gui/flashcard-modal.tsx | 35 ++- styles.css | 197 ++++++------- 4 files changed, 392 insertions(+), 353 deletions(-) diff --git a/src/gui/DecksListView.tsx b/src/gui/DecksListView.tsx index 71ab313c..66b079cb 100644 --- a/src/gui/DecksListView.tsx +++ b/src/gui/DecksListView.tsx @@ -79,14 +79,18 @@ export class DecksListView { this._createTree(deck, this.content); } - this.view.removeClass("sr-is-hidden"); + if(this.view.hasClass("sr-is-hidden")){ + this.view.removeClass("sr-is-hidden"); + } } /** * Hides the DeckListView */ hide() { - this.view.addClass("sr-is-hidden"); + if(!this.view.hasClass("sr-is-hidden")){ + this.view.addClass("sr-is-hidden"); + } } private _createHeaderStats() { diff --git a/src/gui/FlashcardReviewView.tsx b/src/gui/FlashcardReviewView.tsx index 256b35b3..df06beca 100644 --- a/src/gui/FlashcardReviewView.tsx +++ b/src/gui/FlashcardReviewView.tsx @@ -20,19 +20,29 @@ import { FlashcardModalMode } from "./flashcard-modal"; export class FlashcardReviewView { public app: App; public plugin: SRPlugin; - public answerBtn: HTMLElement; - public titleEl: HTMLElement; - public contentEl: HTMLElement; - public flashcardView: HTMLElement; - private flashCardMenu: HTMLDivElement; - public hardBtn: HTMLElement; - public goodBtn: HTMLElement; - public easyBtn: HTMLElement; - public nextBtn: HTMLElement; - public responseDiv: HTMLElement; + public modalContentEl: HTMLElement; + + public view: HTMLDivElement; + + public header: HTMLDivElement; + public title: HTMLDivElement; + public backButton: HTMLButtonElement; + + public controls: HTMLDivElement; + public editButton: HTMLButtonElement; public resetButton: HTMLButtonElement; - public editButton: HTMLElement; - public contextView: HTMLElement; + public infoButton: HTMLButtonElement; + public skipButton: HTMLButtonElement; + + public content: HTMLDivElement; + public context: HTMLElement; + + public response: HTMLDivElement; + public hardButton: HTMLButtonElement; + public goodButton: HTMLButtonElement; + public easyButton: HTMLButtonElement; + public answerButton: HTMLButtonElement; + public mode: FlashcardModalMode; private reviewSequencer: IFlashcardReviewSequencer; private settings: SRSettings; @@ -40,25 +50,12 @@ export class FlashcardReviewView { private backClickHandler: () => void; private editClickHandler: () => void; - private get currentCard(): Card { - return this.reviewSequencer.currentCard; - } - - private get currentQuestion(): Question { - return this.reviewSequencer.currentQuestion; - } - - private get currentNote(): Note { - return this.reviewSequencer.currentNote; - } - constructor( app: App, plugin: SRPlugin, settings: SRSettings, reviewSequencer: IFlashcardReviewSequencer, reviewMode: FlashcardReviewMode, - titleEl: HTMLElement, contentEl: HTMLElement, backClickHandler: () => void, editClickHandler: () => void, @@ -71,22 +68,194 @@ export class FlashcardReviewView { this.backClickHandler = backClickHandler; this.editClickHandler = editClickHandler; - this.titleEl = titleEl; - this.contentEl = contentEl; + this.modalContentEl = contentEl; - this.titleEl.addClass("sr-centered"); + document.addEventListener("keydown", this._keydownHandler.bind(this)); - this.contentEl.style.position = "relative"; - this.contentEl.style.height = "92%"; - this.contentEl.addClass("sr-modal-content"); - if (Platform.isMobile) { - this.contentEl.style.display = "block"; + this.init(); + } + + /** + * Initializes all Elements in the FlashcardView + */ + init() { + this.view = this.modalContentEl.createDiv(); + this.view.addClasses(["sr-flashcard", "sr-is-hidden"]); + + this.header = this.view.createDiv(); + this.header.addClass("sr-header"); + + this._createBackButton(); + + this.title = this.header.createDiv(); + this.title.addClass("sr-title"); + + this.controls = this.header.createDiv(); + this.controls.addClass("sr-controls"); + + this._createControls(); + + if (this.settings.showContextInCards) { + this.context = this.view.createDiv(); + this.context.addClass("sr-context"); + } + + this.content = this.view.createDiv(); + this.content.addClass("sr-content"); + + this.response = this.view.createDiv(); + this.response.addClass("sr-response"); + + this._createResponseButtons(); + } + + /** + * Shows the FlashcardView + */ + async show() { + this.mode = FlashcardModalMode.Front; + const deck: Deck = this.reviewSequencer.currentDeck; + + this._setTitle(deck); + this.resetButton.disabled = true; + + if (this.settings.showContextInCards) { + this.context.setText( + this._formatQuestionContextText(this._currentQuestion.questionContext), + ); + } + + this.content.empty(); + + const wrapper: RenderMarkdownWrapper = new RenderMarkdownWrapper( + this.app, + this.plugin, + this._currentNote.filePath, + ); + await wrapper.renderMarkdownWrapper(this._currentCard.front, this.content); + + this._resetResponseButtons(); + + if (this.view.hasClass("sr-is-hidden")) { + this.view.removeClass("sr-is-hidden"); + } + } + + /** + * Hides the FlashcardView + */ + hide() { + if (!this.view.hasClass("sr-is-hidden")) { + this.view.addClass("sr-is-hidden"); } + } + + private _createBackButton() { + this.backButton = this.header.createEl("button"); + this.backButton.addClasses(["sr-button", "sr-back-button"]); + setIcon(this.backButton, "arrow-left"); + this.backButton.setAttribute("aria-label", t("BACK")); + this.backButton.addEventListener("click", () => { + /* this.plugin.data.historyDeck = ""; */ + this.backClickHandler(); + }); + } + + private _setTitle(deck: Deck) { + this.title.setText(`${deck.deckName}: ${deck.getCardCount(CardListType.All, true)}`); + } + + private _createControls() { + this._createEditButton(); + this._createResetButton(); + this._createCardInfoButton(); + this._createSkipButton(); + } + + private _createEditButton() { + this.editButton = this.controls.createEl("button"); + this.editButton.addClasses(["sr-button", "sr-edit-button"]); + setIcon(this.editButton, "edit"); + this.editButton.setAttribute("aria-label", t("EDIT_CARD")); + this.editButton.addEventListener("click", async () => { + this.editClickHandler(); + }); + } + + private _createResetButton() { + this.resetButton = this.controls.createEl("button"); + this.resetButton.addClasses(["sr-button", "sr-reset-button"]); + setIcon(this.resetButton, "refresh-cw"); + this.resetButton.setAttribute("aria-label", t("RESET_CARD_PROGRESS")); + this.resetButton.addEventListener("click", () => { + this._processReview(ReviewResponse.Reset); + }); + } + + private _createCardInfoButton() { + this.infoButton = this.controls.createEl("button"); + this.infoButton.addClasses(["sr-button", "sr-info-button"]); + setIcon(this.infoButton, "info"); + this.infoButton.setAttribute("aria-label", "View Card Info"); + this.infoButton.addEventListener("click", async () => { + this._displayCurrentCardInfoNotice(); + }); + } + + private _createSkipButton() { + this.skipButton = this.controls.createEl("button"); + this.skipButton.addClasses(["sr-button", "sr-skip-button"]); + setIcon(this.skipButton, "chevrons-right"); + this.skipButton.setAttribute("aria-label", t("SKIP")); + this.skipButton.addEventListener("click", () => { + this._skipCurrentCard(); + }); + } + + private _createResponseButtons() { + this._createShowAnswerButton(); + this._createHardButton(); + this._createGoodButton(); + this._createEasyButton(); + } + + private _createShowAnswerButton() { + this.answerButton = this.response.createEl("button"); + this.answerButton.addClasses(["sr-response-button", "sr-show-answer-button", "sr-bg-blue"]); + this.answerButton.setText(t("SHOW_ANSWER")); + this.answerButton.addEventListener("click", () => { + this._showAnswer(); + }); + } + + private _createHardButton() { + this.hardButton = this.response.createEl("button"); + this.hardButton.addClasses(["sr-response-button", "sr-hard-button", "sr-bg-red", "sr-is-hidden"]); + this.hardButton.setText(this.settings.flashcardHardText); + this.hardButton.addEventListener("click", () => { + this._processReview(ReviewResponse.Hard); + }); + } + + private _createGoodButton() { + this.goodButton = this.response.createEl("button"); + this.goodButton.addClasses(["sr-response-button", "sr-good-button", "sr-bg-blue", "sr-is-hidden"]); + this.goodButton.setText(this.settings.flashcardGoodText); + this.goodButton.addEventListener("click", () => { + this._processReview(ReviewResponse.Good); + }); + } - document.addEventListener("keydown", this.keydownHandler.bind(this)); + private _createEasyButton() { + this.easyButton = this.response.createEl("button"); + this.easyButton.addClasses(["sr-response-button", "sr-hard-button", "sr-bg-green", "sr-is-hidden"]); + this.easyButton.setText(this.settings.flashcardEasyText); + this.easyButton.addEventListener("click", () => { + this._processReview(ReviewResponse.Easy); + }); } - keydownHandler(e: KeyboardEvent): void { + private _keydownHandler(e: KeyboardEvent): void { // Checks if the input textbox is in focus before processing keyboard shortcuts. if ( document.activeElement.nodeName === "TEXTAREA" || @@ -103,15 +272,15 @@ export class FlashcardReviewView { switch (e.code) { case "KeyS": - this.skipCurrentCard(); + this._skipCurrentCard(); consumeKeyEvent(); break; case "Space": if (this.mode === FlashcardModalMode.Front) { - this.showAnswer(); + this._showAnswer(); consumeKeyEvent(); } else if (this.mode === FlashcardModalMode.Back) { - this.processReview(ReviewResponse.Good); + this._processReview(ReviewResponse.Good); consumeKeyEvent(); } break; @@ -120,7 +289,7 @@ export class FlashcardReviewView { if (this.mode !== FlashcardModalMode.Front) { break; } - this.showAnswer(); + this._showAnswer(); consumeKeyEvent(); break; case "Numpad1": @@ -128,7 +297,7 @@ export class FlashcardReviewView { if (this.mode !== FlashcardModalMode.Back) { break; } - this.processReview(ReviewResponse.Hard); + this._processReview(ReviewResponse.Hard); consumeKeyEvent(); break; case "Numpad2": @@ -136,7 +305,7 @@ export class FlashcardReviewView { if (this.mode !== FlashcardModalMode.Back) { break; } - this.processReview(ReviewResponse.Good); + this._processReview(ReviewResponse.Good); consumeKeyEvent(); break; case "Numpad3": @@ -144,7 +313,7 @@ export class FlashcardReviewView { if (this.mode !== FlashcardModalMode.Back) { break; } - this.processReview(ReviewResponse.Easy); + this._processReview(ReviewResponse.Easy); consumeKeyEvent(); break; case "Numpad0": @@ -152,7 +321,7 @@ export class FlashcardReviewView { if (this.mode !== FlashcardModalMode.Back) { break; } - this.processReview(ReviewResponse.Reset); + this._processReview(ReviewResponse.Reset); consumeKeyEvent(); break; default: @@ -160,242 +329,120 @@ export class FlashcardReviewView { } } - async showCurrentCard(): Promise { - this.setupView(); - - const deck: Deck = this.reviewSequencer.currentDeck; - - this.responseDiv.style.display = "none"; - this.resetButton.disabled = true; - this.titleEl.setText(`${deck.deckName}: ${deck.getCardCount(CardListType.All, true)}`); - - this.answerBtn.style.display = "initial"; - this.flashcardView.empty(); - this.mode = FlashcardModalMode.Front; - - const wrapper: RenderMarkdownWrapper = new RenderMarkdownWrapper( - this.app, - this.plugin, - this.currentNote.filePath, - ); - await wrapper.renderMarkdownWrapper(this.currentCard.front, this.flashcardView); - - if (this.reviewMode == FlashcardReviewMode.Cram) { - // Same for mobile/desktop - this.hardBtn.setText(`${this.settings.flashcardHardText}`); - this.easyBtn.setText(`${this.settings.flashcardEasyText}`); - } else { - this.setupEaseButton( - this.hardBtn, - this.settings.flashcardHardText, - ReviewResponse.Hard, - ); - this.setupEaseButton( - this.goodBtn, - this.settings.flashcardGoodText, - ReviewResponse.Good, - ); - this.setupEaseButton( - this.easyBtn, - this.settings.flashcardEasyText, - ReviewResponse.Easy, - ); - } - - if (this.settings.showContextInCards) - this.contextView.setText( - this.formatQuestionContextText(this.currentQuestion.questionContext), - ); - } - - createShowAnswerButton() { - this.answerBtn = this.contentEl.createDiv(); - this.answerBtn.setAttribute("id", "sr-show-answer"); - this.answerBtn.setText(t("SHOW_ANSWER")); - this.answerBtn.addEventListener("click", () => { - this.showAnswer(); - }); - } - - createResponseButtons() { - this.responseDiv = this.contentEl.createDiv("sr-flashcard-response"); - - this.hardBtn = document.createElement("button"); - this.hardBtn.setAttribute("id", "sr-hard-btn"); - this.hardBtn.setText(this.settings.flashcardHardText); - this.hardBtn.addEventListener("click", () => { - this.processReview(ReviewResponse.Hard); - }); - this.responseDiv.appendChild(this.hardBtn); - - this.goodBtn = document.createElement("button"); - this.goodBtn.setAttribute("id", "sr-good-btn"); - this.goodBtn.setText(this.settings.flashcardGoodText); - this.goodBtn.addEventListener("click", () => { - this.processReview(ReviewResponse.Good); - }); - this.responseDiv.appendChild(this.goodBtn); - - this.easyBtn = document.createElement("button"); - this.easyBtn.setAttribute("id", "sr-easy-btn"); - this.easyBtn.setText(this.settings.flashcardEasyText); - this.easyBtn.addEventListener("click", () => { - this.processReview(ReviewResponse.Easy); - }); - this.responseDiv.appendChild(this.easyBtn); - this.responseDiv.style.display = "none"; - } - - createSkipButton() { - const skipButton = this.flashCardMenu.createEl("button"); - skipButton.addClass("sr-flashcard-menu-item"); - setIcon(skipButton, "chevrons-right"); - skipButton.setAttribute("aria-label", t("SKIP")); - skipButton.addEventListener("click", () => { - this.skipCurrentCard(); - }); - } - - createCardInfoButton() { - const cardInfo = this.flashCardMenu.createEl("button"); - cardInfo.addClass("sr-flashcard-menu-item"); - setIcon(cardInfo, "info"); - cardInfo.setAttribute("aria-label", "View Card Info"); - cardInfo.addEventListener("click", async () => { - this.displayCurrentCardInfoNotice(); - }); - } - - displayCurrentCardInfoNotice() { - const schedule = this.currentCard.scheduleInfo; + private _displayCurrentCardInfoNotice() { + const schedule = this._currentCard.scheduleInfo; const currentEaseStr = t("CURRENT_EASE_HELP_TEXT") + (schedule?.ease ?? t("NEW")); const currentIntervalStr = t("CURRENT_INTERVAL_HELP_TEXT") + textInterval(schedule?.interval, false); const generatedFromStr = t("CARD_GENERATED_FROM", { - notePath: this.currentQuestion.note.filePath, + notePath: this._currentQuestion.note.filePath, }); new Notice(currentEaseStr + "\n" + currentIntervalStr + "\n" + generatedFromStr); } - createBackButton() { - const backButton = this.flashCardMenu.createEl("button"); - backButton.addClass("sr-flashcard-menu-item"); - setIcon(backButton, "arrow-left"); - backButton.setAttribute("aria-label", t("BACK")); - backButton.addEventListener("click", () => { - /* this.plugin.data.historyDeck = ""; */ - this.backClickHandler(); - }); + private _resetResponseButtons() { + this.answerButton.removeClass("sr-is-hidden"); + this.hardButton.addClass("sr-is-hidden"); + this.goodButton.addClass("sr-is-hidden"); + this.easyButton.addClass("sr-is-hidden"); } - createResetButton() { - this.resetButton = this.flashCardMenu.createEl("button"); - this.resetButton.addClass("sr-flashcard-menu-item"); - setIcon(this.resetButton, "refresh-cw"); - this.resetButton.setAttribute("aria-label", t("RESET_CARD_PROGRESS")); - this.resetButton.addEventListener("click", () => { - this.processReview(ReviewResponse.Reset); - }); + private get _currentCard(): Card { + return this.reviewSequencer.currentCard; } - createEditButton() { - this.editButton = this.flashCardMenu.createEl("button"); - this.editButton.addClass("sr-flashcard-menu-item"); - setIcon(this.editButton, "edit"); - this.editButton.setAttribute("aria-label", t("EDIT_CARD")); - this.editButton.addEventListener("click", async () => { - this.editClickHandler(); - }); + private get _currentQuestion(): Question { + return this.reviewSequencer.currentQuestion; } - private setupView(): void { - this.contentEl.empty(); - - this.flashCardMenu = this.contentEl.createDiv("sr-flashcard-menu"); - - this.createBackButton(); - this.createEditButton(); - this.createResetButton(); - this.createCardInfoButton(); - this.createSkipButton(); - - if (this.settings.showContextInCards) { - this.contextView = this.contentEl.createDiv(); - this.contextView.setAttribute("id", "sr-context"); - } - - this.flashcardView = this.contentEl.createDiv("div"); - this.flashcardView.setAttribute("id", "sr-flashcard-view"); - - this.createResponseButtons(); - - this.createShowAnswerButton(); - - if (this.reviewMode == FlashcardReviewMode.Cram) { - this.goodBtn.style.display = "none"; - - this.responseDiv.addClass("sr-ignorestats-response"); - this.easyBtn.addClass("sr-ignorestats-btn"); - this.hardBtn.addClass("sr-ignorestats-btn"); - } + private get _currentNote(): Note { + return this.reviewSequencer.currentNote; } - private showAnswer(): void { + private _showAnswer(): void { this.mode = FlashcardModalMode.Back; - this.answerBtn.style.display = "none"; - this.responseDiv.style.display = "grid"; - - if (this.currentCard.hasSchedule) { + if (this._currentCard.hasSchedule) { this.resetButton.disabled = false; } - if (this.currentQuestion.questionType !== CardType.Cloze) { + if (this._currentQuestion.questionType !== CardType.Cloze) { const hr: HTMLElement = document.createElement("hr"); - hr.setAttribute("id", "sr-hr-card-divide"); - this.flashcardView.appendChild(hr); + hr.addClass("sr-card-divide"); + this.content.appendChild(hr); } else { - this.flashcardView.empty(); + this.content.empty(); } const wrapper: RenderMarkdownWrapper = new RenderMarkdownWrapper( this.app, this.plugin, - this.currentNote.filePath, + this._currentNote.filePath, ); - wrapper.renderMarkdownWrapper(this.currentCard.back, this.flashcardView); + wrapper.renderMarkdownWrapper(this._currentCard.back, this.content); + + this.answerButton.addClass("sr-is-hidden"); + this.hardButton.removeClass("sr-is-hidden"); + this.easyButton.removeClass("sr-is-hidden"); + + if (this.reviewMode === FlashcardReviewMode.Cram) { + this.response.addClass("is-cram"); + this.hardButton.setText(`${this.settings.flashcardHardText}`); + this.easyButton.setText(`${this.settings.flashcardEasyText}`); + } else { + this.goodButton.removeClass("sr-is-hidden"); + this._setupEaseButton( + this.hardButton, + this.settings.flashcardHardText, + ReviewResponse.Hard, + ); + this._setupEaseButton( + this.goodButton, + this.settings.flashcardGoodText, + ReviewResponse.Good, + ); + this._setupEaseButton( + this.easyButton, + this.settings.flashcardEasyText, + ReviewResponse.Easy, + ); + } } - private async processReview(response: ReviewResponse): Promise { + private async _processReview(response: ReviewResponse): Promise { await this.reviewSequencer.processReview(response); // console.log(`processReview: ${response}: ${this.currentCard?.front ?? 'None'}`) - await this.handleNextCard(); + await this._handleSkipCard(); } - private async skipCurrentCard(): Promise { + private async _skipCurrentCard(): Promise { this.reviewSequencer.skipCurrentCard(); // console.log(`skipCurrentCard: ${this.currentCard?.front ?? 'None'}`) - await this.handleNextCard(); + await this._handleSkipCard(); } - private async handleNextCard(): Promise { - if (this.currentCard != null) await this.showCurrentCard(); + private async _handleSkipCard(): Promise { + if (this._currentCard != null) await this.show(); else this.backClickHandler(); } - private formatQuestionContextText(questionContext: string[]): string { - const result = `${this.currentNote.file.basename} > ${questionContext.join(" > ")}`; - return result; + private _formatQuestionContextText(questionContext: string[]): string { + const separator: string = " > "; + let result = this._currentNote.file.basename; + if (questionContext.length > 0) { + result += separator + questionContext.join(separator); + } + return result + separator + "..."; } - private setupEaseButton( + private _setupEaseButton( button: HTMLElement, buttonName: string, reviewResponse: ReviewResponse, ) { const schedule: CardScheduleInfo = this.reviewSequencer.determineCardSchedule( reviewResponse, - this.currentCard, + this._currentCard, ); const interval: number = schedule.interval; diff --git a/src/gui/flashcard-modal.tsx b/src/gui/flashcard-modal.tsx index 787804a1..5e77828e 100644 --- a/src/gui/flashcard-modal.tsx +++ b/src/gui/flashcard-modal.tsx @@ -29,6 +29,7 @@ export class FlashcardModal extends Modal { private settings: SRSettings; private reviewMode: FlashcardReviewMode; private deckView: DecksListView; + private flashcardView: FlashcardReviewView; constructor( app: App, @@ -60,6 +61,17 @@ export class FlashcardModal extends Modal { this.contentEl, this.startReviewOfDeck.bind(this), ); + + this.flashcardView = new FlashcardReviewView( + this.app, + this.plugin, + this.settings, + this.reviewSequencer, + this.reviewMode, + this.contentEl, + this.showDecksList.bind(this), + this.doEditQuestionText.bind(this), + ); } onOpen(): void { @@ -71,6 +83,7 @@ export class FlashcardModal extends Modal { } showDecksList(): void { + this.hideFlashcard(); this.deckView.show(); } @@ -78,21 +91,19 @@ export class FlashcardModal extends Modal { this.deckView.hide(); } - startReviewOfDeck(deck: Deck) { + showFlashcard(): void { this.hideDecksList(); + this.flashcardView.show(); + } + + hideFlashcard(): void { + this.flashcardView.hide(); + } + + startReviewOfDeck(deck: Deck) { this.reviewSequencer.setCurrentDeck(deck.getTopicPath()); if (this.reviewSequencer.hasCurrentCard) { - new FlashcardReviewView( - this.app, - this.plugin, - this.settings, - this.reviewSequencer, - this.reviewMode, - this.titleEl, - this.contentEl, - this.showDecksList.bind(this), - this.doEditQuestionText.bind(this), - ).showCurrentCard(); + this.showFlashcard(); } else { this.showDecksList(); } diff --git a/styles.css b/styles.css index 730a8777..cd917469 100644 --- a/styles.css +++ b/styles.css @@ -11,25 +11,40 @@ body:not(.native-scrollbars) .sr-modal .modal-close-button { } .sr-is-hidden { - display: none; + display: none !important; } .sr-bg-blue, .sr-bg-green, .sr-bg-red { - color: #ffffff; + color: #ffffff !important; } .sr-bg-green { - background-color: #4caf50; + background-color: #4caf50 !important; } .sr-bg-blue { - background-color: #2094f3; + background-color: #2094f3 !important; } .sr-bg-red { - background-color: #ff7043; + background-color: #ff7043 !important; +} + +.sr-deck-list .sr-tree-item-row:hover .sr-bg-green, +.sr-flashcard .sr-response-button.sr-bg-green:hover { + background-color: hsl(122, 39%, 44%) !important; +} + +.sr-deck-list .sr-tree-item-row:hover .sr-bg-blue, +.sr-flashcard .sr-response-button.sr-bg-blue:hover { + background-color: hsl(207, 90%, 49%) !important; +} + +.sr-deck-list .sr-tree-item-row:hover .sr-bg-red, +.sr-flashcard .sr-response-button.sr-bg-red:hover { + background-color: hsl(14, 100%, 58%) !important; } .sr-deck-list, @@ -37,26 +52,29 @@ body:not(.native-scrollbars) .sr-modal .modal-close-button { .sr-edit-view { display: flex; flex-direction: column; - gap: 20px; width: 100%; height: 100%; } -.sr-deck-list .sr-header { +.sr-header { display: flex; flex-direction: column; - gap: 8px; - padding-bottom: 14px; - width: 100%; justify-content: center; align-items: center; + width: 100%; border-bottom: 1px solid var(--hr-color); } -.sr-deck-list .sr-title { +.sr-deck-list .sr-header { + gap: 8px; + padding-bottom: 14px; + margin-bottom: 24px; +} + +.sr-title { font-size: var(--font-ui-large); font-weight: var(--font-semibold); - text-align: left; + text-align: center; line-height: var(--line-height-tight); } @@ -87,18 +105,6 @@ body:not(.native-scrollbars) .sr-modal .modal-close-button { margin-bottom: 0; } -.sr-deck-list .sr-tree-item-row:hover .sr-bg-green { - background-color: hsl(122, 39%, 44%); -} - -.sr-deck-list .sr-tree-item-row:hover .sr-bg-blue { - background-color: hsl(207, 90%, 49%); -} - -.sr-deck-list .sr-tree-item-row:hover .sr-bg-red { - background-color: hsl(14, 100%, 58%); -} - .sr-deck-list .sr-tree-stats-container { display: flex; gap: 4px; @@ -112,122 +118,104 @@ body:not(.native-scrollbars) .sr-modal .modal-close-button { color: #ffffff !important; } -.sr-flashcard-menu { - width: 100%; - display: flex; - justify-content: center; - align-items: center; - flex-direction: row; - gap: 1rem; +.sr-flashcard .sr-header { + position: relative; + gap: 8px; + padding-bottom: 8px; } -.sr-flashcard-menu-item { +.sr-flashcard .sr-button { box-shadow: none !important; cursor: pointer; } -.sr-flashcard-menu-item:disabled { - cursor: not-allowed; +.sr-flashcard .sr-button:hover { + background-color: var(--background-modifier-hover); } -.sr-flashcard-input-modal { - height: 80%; -} - -.sr-flashcard-input-area { - height: 80%; +.sr-flashcard .sr-button:disabled { + cursor: not-allowed; } -.sr-flashcard-input-area > textarea { - height: 100%; +.sr-flashcard .sr-back-button { + position: absolute; + left: 0; + top: 0; + z-index: 21; } -.sr-flashcard-edit-button-bar { +.sr-flashcard .sr-controls { display: flex; - flex-direction: row-reverse; - justify-content: space-between; - width: 100%; - margin-top: 1rem; + gap: var(--size-4-4); } -.sr-flashcard-response { - display: inline-grid; +.sr-flashcard .sr-context { + font-style: italic; + color: var(--text-faint); + display: block; width: 100%; - grid-template-columns: auto auto auto; - position: absolute; - bottom: 0; + margin-top: 12px; } -.sr-ignorestats-btn { +.sr-flashcard .sr-content { + font-size: var(--font-text-size); + overflow-y: auto; + user-select: text; + padding-inline: 8px; width: 100%; + flex-grow: 1; } -.sr-ignorestats-response { - grid-template-columns: auto auto; - gap: var(--size-4-4); +.sr-flashcard .sr-card-divide { + backdrop-filter: invert(40%); + border-top-style: dashed; } -.sr-centered { +.sr-flashcard .sr-response { display: flex; - justify-content: center; - align-items: center; - flex-direction: column; + width: 100%; + margin-top: var(--size-4-4); + gap: var(--size-4-4); } -#sr-show-answer { +.sr-flashcard .sr-response-button { height: 48px; + flex-grow: 1; + margin: auto; line-height: 48px; - width: 100%; text-align: center; - position: absolute; - bottom: 0; cursor: pointer; - background-color: #2196f3; - color: #ffffff; border-radius: 4px; user-select: text; } -#sr-hr-card-divide { - backdrop-filter: invert(40%); - border: none; - height: 2px; -} - -#sr-hard-btn, -#sr-good-btn, -#sr-easy-btn { - height: 48px; - margin: auto; - color: #ffffff; - cursor: pointer; -} +/* OLD stuff */ -#sr-hard-btn { - background-color: #f44336; +.sr-flashcard-input-modal { + height: 80%; } -#sr-good-btn { - background-color: #2196f3; +.sr-flashcard-input-area { + height: 80%; } -#sr-easy-btn { - background-color: #4caf50; +.sr-flashcard-input-area > textarea { + height: 100%; } -#sr-context { - font-style: italic; - font-weight: bold; - margin-top: 16px; - display: block; +.sr-flashcard-edit-button-bar { + display: flex; + flex-direction: row-reverse; + justify-content: space-between; width: 100%; + margin-top: 1rem; } -#sr-flashcard-view { - font-size: var(--font-text-size); - overflow-y: auto; - height: 80%; - user-select: text; +.sr-centered { + display: flex; + justify-content: center; + align-items: center; + flex-direction: column; } #sr-chart-period { @@ -236,7 +224,7 @@ body:not(.native-scrollbars) .sr-modal .modal-close-button { } @media only screen and (max-width: 600px) { - .sr-back-btn { + .sr-back-button { width: initial !important; } @@ -245,19 +233,8 @@ body:not(.native-scrollbars) .sr-modal .modal-close-button { } .sr-modal-content::-webkit-scrollbar, - #sr-flashcard-view::-webkit-scrollbar { + .sr-deck-list .sr-content::-webkit-scrollbar, + .sr-flashcard .sr-content::-webkit-scrollbar { display: none; } - - .sr-flashcard-response, - #sr-show-answer { - width: 93.5% !important; - line-height: 60px; - } - - #sr-hard-btn, - #sr-good-btn, - #sr-easy-btn { - width: 100px; - } } \ No newline at end of file From 2ab3c10cba84ba1cfde8b3b265a3b74fd45b60e9 Mon Sep 17 00:00:00 2001 From: KyleKlus Date: Mon, 12 Feb 2024 10:01:22 +0100 Subject: [PATCH 15/37] UPDATE: Redesigned the edit modal --- ...dit-modal.ts => flashcards-edit-modal.tsx} | 79 +++++++++++-------- styles.css | 54 ++++++++----- 2 files changed, 78 insertions(+), 55 deletions(-) rename src/gui/{flashcards-edit-modal.ts => flashcards-edit-modal.tsx} (57%) diff --git a/src/gui/flashcards-edit-modal.ts b/src/gui/flashcards-edit-modal.tsx similarity index 57% rename from src/gui/flashcards-edit-modal.ts rename to src/gui/flashcards-edit-modal.tsx index a6c0c1e4..3c1169de 100644 --- a/src/gui/flashcards-edit-modal.ts +++ b/src/gui/flashcards-edit-modal.tsx @@ -6,6 +6,12 @@ export class FlashcardEditModal extends Modal { public input: string; public waitForClose: Promise; + public title: HTMLDivElement; + public textArea: HTMLTextAreaElement; + public response: HTMLDivElement; + public saveButton: HTMLButtonElement; + public cancelButton: HTMLButtonElement; + private resolvePromise: (input: string) => void; // eslint-disable-next-line @typescript-eslint/no-explicit-any private rejectPromise: (reason?: any) => void; @@ -17,10 +23,10 @@ export class FlashcardEditModal extends Modal { const newPromptModal = new FlashcardEditModal(app, placeholder); return newPromptModal.waitForClose; } + constructor(app: App, existingText: string) { super(app); - this.titleEl.setText(t("EDIT_CARD")); - this.titleEl.addClass("sr-centered"); + this.modalText = existingText; this.input = existingText; @@ -28,50 +34,55 @@ export class FlashcardEditModal extends Modal { this.resolvePromise = resolve; this.rejectPromise = reject; }); - this.display(); + + this.modalEl.addClass("sr-edit-modal"); + + this.init(); this.open(); } - private display() { + /** + * Initializes all components of the EditModal + */ + init() { this.contentEl.empty(); - this.modalEl.addClass("sr-flashcard-input-modal"); + this.contentEl.addClass("sr-edit-view"); + + this.title = this.contentEl.createDiv(); + this.title.setText(t("EDIT_CARD")); + this.title.addClass("sr-title"); - const mainContentContainer: HTMLDivElement = this.contentEl.createDiv(); - mainContentContainer.addClass("sr-flashcard-input-area"); - this.inputComponent = this.createInputField(mainContentContainer, this.modalText); - this.createButtonBar(mainContentContainer); + this.textArea = this.contentEl.createEl("textarea"); + this.textArea.addClass("sr-input"); + this.textArea.setText(this.modalText ?? ""); + this.textArea.addEventListener("keydown", this.submitEnterCallback); + + this.createResponse(this.contentEl); } - private createButton( + private _createResponseButton( container: HTMLElement, text: string, + colorClass: string, callback: (evt: MouseEvent) => void, ) { - const btn = new ButtonComponent(container); - btn.setButtonText(text).onClick(callback); - return btn; + const button = container.createEl("button"); + button.addClasses(["sr-response-button", colorClass]); + button.setText(text); + button.addEventListener("click", callback); } - private createButtonBar(mainContentContainer: HTMLDivElement) { - const buttonBarContainer: HTMLDivElement = mainContentContainer.createDiv(); - buttonBarContainer.addClass("sr-flashcard-edit-button-bar"); - this.createButton( - buttonBarContainer, + private createResponse(mainContentContainer: HTMLElement) { + const response: HTMLDivElement = mainContentContainer.createDiv(); + response.addClass("sr-response"); + this._createResponseButton(response, t("CANCEL"), "sr-bg-red", this.cancelClickCallback); + this._createResponseButton(response, "", "sr-spacer", () => { }); + this._createResponseButton( + response, t("SAVE"), + "sr-bg-green", this.submitClickCallback, - ).setCta().buttonEl.style.marginRight = "0"; - this.createButton(buttonBarContainer, t("CANCEL"), this.cancelClickCallback); - } - - protected createInputField(container: HTMLElement, value: string) { - const textComponent = new TextAreaComponent(container); - - textComponent.inputEl.style.width = "100%"; - textComponent - .setValue(value ?? "") - .inputEl.addEventListener("keydown", this.submitEnterCallback); - - return textComponent; + ); } private submitClickCallback = (_: MouseEvent) => this.submit(); @@ -86,7 +97,7 @@ export class FlashcardEditModal extends Modal { private submit() { this.didSubmit = true; - this.input = this.inputComponent.getValue(); + this.input = this.textArea.value; this.close(); } @@ -97,7 +108,7 @@ export class FlashcardEditModal extends Modal { onOpen() { super.onOpen(); - this.inputComponent.inputEl.focus(); + this.textArea.focus(); } onClose() { @@ -112,6 +123,6 @@ export class FlashcardEditModal extends Modal { } private removeInputListener() { - this.inputComponent.inputEl.removeEventListener("keydown", this.submitEnterCallback); + this.textArea.removeEventListener("keydown", this.submitEnterCallback); } } diff --git a/styles.css b/styles.css index cd917469..ed645986 100644 --- a/styles.css +++ b/styles.css @@ -33,17 +33,17 @@ body:not(.native-scrollbars) .sr-modal .modal-close-button { } .sr-deck-list .sr-tree-item-row:hover .sr-bg-green, -.sr-flashcard .sr-response-button.sr-bg-green:hover { +.sr-response-button.sr-bg-green:hover { background-color: hsl(122, 39%, 44%) !important; } .sr-deck-list .sr-tree-item-row:hover .sr-bg-blue, -.sr-flashcard .sr-response-button.sr-bg-blue:hover { +.sr-response-button.sr-bg-blue:hover { background-color: hsl(207, 90%, 49%) !important; } .sr-deck-list .sr-tree-item-row:hover .sr-bg-red, -.sr-flashcard .sr-response-button.sr-bg-red:hover { +.sr-response-button.sr-bg-red:hover { background-color: hsl(14, 100%, 58%) !important; } @@ -171,14 +171,14 @@ body:not(.native-scrollbars) .sr-modal .modal-close-button { border-top-style: dashed; } -.sr-flashcard .sr-response { +.sr-response { display: flex; width: 100%; margin-top: var(--size-4-4); gap: var(--size-4-4); } -.sr-flashcard .sr-response-button { +.sr-response-button { height: 48px; flex-grow: 1; margin: auto; @@ -189,28 +189,44 @@ body:not(.native-scrollbars) .sr-modal .modal-close-button { user-select: text; } -/* OLD stuff */ +.sr-edit-modal { + height: 80% +} -.sr-flashcard-input-modal { - height: 80%; +.sr-edit-view { + height: 100%; + width: 100%; + display: flex; + flex-direction: column; + justify-content: center; + align-items: center; + gap: var(--size-4-4) } -.sr-flashcard-input-area { - height: 80%; +.sr-edit-view .sr-input { + flex-grow: 1; + width: 100%; + resize: none; } -.sr-flashcard-input-area > textarea { - height: 100%; +.sr-edit-view .sr-response { + display: grid; + grid-template-columns: auto auto auto; + width: 100%; + margin-top: 0; } -.sr-flashcard-edit-button-bar { - display: flex; - flex-direction: row-reverse; - justify-content: space-between; +.sr-edit-view .sr-response-button { width: 100%; - margin-top: 1rem; } +.sr-edit-view .sr-response-button.sr-spacer { + opacity: 0; + cursor: default; +} + +/* OLD stuff */ + .sr-centered { display: flex; justify-content: center; @@ -224,10 +240,6 @@ body:not(.native-scrollbars) .sr-modal .modal-close-button { } @media only screen and (max-width: 600px) { - .sr-back-button { - width: initial !important; - } - .sr-modal-content { width: 98% !important; } From ac57c9f2a09c25264e0525ba37005686526514af Mon Sep 17 00:00:00 2001 From: KyleKlus Date: Mon, 12 Feb 2024 10:05:46 +0100 Subject: [PATCH 16/37] UPDATED: Renamed files, such that the naming convention is the same everywhere. --- src/gui/DecksListView.tsx | 6 +++--- ...{flashcard-modal.tsx => FlashcardModal.tsx} | 2 +- src/gui/FlashcardReviewView.tsx | 2 +- ...-edit-modal.tsx => FlashcardsEditModal.tsx} | 3 +-- src/gui/{sidebar.ts => Sidebar.tsx} | 0 src/gui/{stats-modal.tsx => StatsModal.tsx} | 0 src/main.ts | 18 +++++++++--------- 7 files changed, 15 insertions(+), 16 deletions(-) rename src/gui/{flashcard-modal.tsx => FlashcardModal.tsx} (98%) rename src/gui/{flashcards-edit-modal.tsx => FlashcardsEditModal.tsx} (96%) rename src/gui/{sidebar.ts => Sidebar.tsx} (100%) rename src/gui/{stats-modal.tsx => StatsModal.tsx} (100%) diff --git a/src/gui/DecksListView.tsx b/src/gui/DecksListView.tsx index 66b079cb..c678c0e8 100644 --- a/src/gui/DecksListView.tsx +++ b/src/gui/DecksListView.tsx @@ -11,7 +11,7 @@ import { IFlashcardReviewSequencer as IFlashcardReviewSequencer, } from "src/FlashcardReviewSequencer"; import { TopicPath } from "src/TopicPath"; -import { FlashcardModalMode } from "./flashcard-modal"; +import { FlashcardModalMode } from "./FlashcardModal"; export class DecksListView { public plugin: SRPlugin; @@ -79,7 +79,7 @@ export class DecksListView { this._createTree(deck, this.content); } - if(this.view.hasClass("sr-is-hidden")){ + if (this.view.hasClass("sr-is-hidden")) { this.view.removeClass("sr-is-hidden"); } } @@ -88,7 +88,7 @@ export class DecksListView { * Hides the DeckListView */ hide() { - if(!this.view.hasClass("sr-is-hidden")){ + if (!this.view.hasClass("sr-is-hidden")) { this.view.addClass("sr-is-hidden"); } } diff --git a/src/gui/flashcard-modal.tsx b/src/gui/FlashcardModal.tsx similarity index 98% rename from src/gui/flashcard-modal.tsx rename to src/gui/FlashcardModal.tsx index 5e77828e..e58dbbd1 100644 --- a/src/gui/flashcard-modal.tsx +++ b/src/gui/FlashcardModal.tsx @@ -11,7 +11,7 @@ import { FlashcardReviewMode, IFlashcardReviewSequencer as IFlashcardReviewSequencer, } from "src/FlashcardReviewSequencer"; -import { FlashcardEditModal } from "./flashcards-edit-modal"; +import { FlashcardEditModal } from "./FlashcardsEditModal"; import { DecksListView } from "./DecksListView"; import { FlashcardReviewView } from "./FlashcardReviewView"; diff --git a/src/gui/FlashcardReviewView.tsx b/src/gui/FlashcardReviewView.tsx index df06beca..c08f6bb4 100644 --- a/src/gui/FlashcardReviewView.tsx +++ b/src/gui/FlashcardReviewView.tsx @@ -15,7 +15,7 @@ import { import { Note } from "src/Note"; import { RenderMarkdownWrapper } from "src/util/RenderMarkdownWrapper"; import { CardScheduleInfo } from "src/CardSchedule"; -import { FlashcardModalMode } from "./flashcard-modal"; +import { FlashcardModalMode } from "./FlashcardModal"; export class FlashcardReviewView { public app: App; diff --git a/src/gui/flashcards-edit-modal.tsx b/src/gui/FlashcardsEditModal.tsx similarity index 96% rename from src/gui/flashcards-edit-modal.tsx rename to src/gui/FlashcardsEditModal.tsx index 3c1169de..a176b496 100644 --- a/src/gui/flashcards-edit-modal.tsx +++ b/src/gui/FlashcardsEditModal.tsx @@ -1,4 +1,4 @@ -import { App, ButtonComponent, Modal, TextAreaComponent } from "obsidian"; +import { App, Modal } from "obsidian"; import { t } from "src/lang/helpers"; // from https://github.com/chhoumann/quickadd/blob/bce0b4cdac44b867854d6233796e3406dfd163c6/src/gui/GenericInputPrompt/GenericInputPrompt.ts#L5 @@ -16,7 +16,6 @@ export class FlashcardEditModal extends Modal { // eslint-disable-next-line @typescript-eslint/no-explicit-any private rejectPromise: (reason?: any) => void; private didSubmit = false; - private inputComponent: TextAreaComponent; private readonly modalText: string; public static Prompt(app: App, placeholder: string): Promise { diff --git a/src/gui/sidebar.ts b/src/gui/Sidebar.tsx similarity index 100% rename from src/gui/sidebar.ts rename to src/gui/Sidebar.tsx diff --git a/src/gui/stats-modal.tsx b/src/gui/StatsModal.tsx similarity index 100% rename from src/gui/stats-modal.tsx rename to src/gui/StatsModal.tsx diff --git a/src/main.ts b/src/main.ts index 1a46390e..6fbb5e02 100644 --- a/src/main.ts +++ b/src/main.ts @@ -2,9 +2,9 @@ import { Notice, Plugin, TAbstractFile, TFile, getAllTags, FrontMatterCache } fr import * as graph from "pagerank.js"; import { SRSettingTab, SRSettings, DEFAULT_SETTINGS, upgradeSettings } from "src/settings"; -import { FlashcardModal } from "src/gui/flashcard-modal"; -import { StatsModal } from "src/gui/stats-modal"; -import { ReviewQueueListView, REVIEW_QUEUE_VIEW_TYPE } from "src/gui/sidebar"; +import { FlashcardModal } from "src/gui/FlashcardModal"; +import { StatsModal } from "src/gui/StatsModal"; +import { ReviewQueueListView, REVIEW_QUEUE_VIEW_TYPE } from "src/gui/Sidebar"; import { ReviewResponse, schedule } from "src/scheduling"; import { YAML_FRONT_MATTER_REGEX, SCHEDULING_INFO_REGEX } from "src/constants"; import { ReviewDeck, ReviewDeckSelectionModal } from "src/ReviewDeck"; @@ -486,9 +486,9 @@ export default class SRPlugin extends Plugin { if (this.data.settings.showDebugMessages) { console.log( "SR: " + - t("SYNC_TIME_TAKEN", { - t: Date.now() - now.valueOf(), - }), + t("SYNC_TIME_TAKEN", { + t: Date.now() - now.valueOf(), + }), ); } @@ -647,8 +647,8 @@ export default class SRPlugin extends Plugin { fileText = fileText.replace( SCHEDULING_INFO_REGEX, `---\n${schedulingInfo[1]}sr-due: ${dueString}\n` + - `sr-interval: ${interval}\nsr-ease: ${ease}\n` + - `${schedulingInfo[5]}---`, + `sr-interval: ${interval}\nsr-ease: ${ease}\n` + + `${schedulingInfo[5]}---`, ); } else if (YAML_FRONT_MATTER_REGEX.test(fileText)) { // new note with existing YAML front matter @@ -656,7 +656,7 @@ export default class SRPlugin extends Plugin { fileText = fileText.replace( YAML_FRONT_MATTER_REGEX, `---\n${existingYaml[1]}sr-due: ${dueString}\n` + - `sr-interval: ${interval}\nsr-ease: ${ease}\n---`, + `sr-interval: ${interval}\nsr-ease: ${ease}\n---`, ); } else { fileText = From dbdcbffa7ce3b2e96d49abd5bc06c51a913188af Mon Sep 17 00:00:00 2001 From: KyleKlus Date: Mon, 12 Feb 2024 11:07:01 +0100 Subject: [PATCH 17/37] UPDATE: Code cleanup & added comment --- .../{DecksListView.tsx => DeckListView.tsx} | 49 ++- ...{FlashcardsEditModal.tsx => EditModal.tsx} | 99 ++++--- src/gui/FlashcardModal.tsx | 41 +-- src/gui/FlashcardReviewView.tsx | 280 ++++++++++-------- src/main.ts | 12 +- styles.css | 6 +- 6 files changed, 280 insertions(+), 207 deletions(-) rename src/gui/{DecksListView.tsx => DeckListView.tsx} (86%) rename src/gui/{FlashcardsEditModal.tsx => EditModal.tsx} (74%) diff --git a/src/gui/DecksListView.tsx b/src/gui/DeckListView.tsx similarity index 86% rename from src/gui/DecksListView.tsx rename to src/gui/DeckListView.tsx index c678c0e8..87613598 100644 --- a/src/gui/DecksListView.tsx +++ b/src/gui/DeckListView.tsx @@ -13,7 +13,7 @@ import { import { TopicPath } from "src/TopicPath"; import { FlashcardModalMode } from "./FlashcardModal"; -export class DecksListView { +export class DeckListView { public plugin: SRPlugin; public mode: FlashcardModalMode; public modalContentEl: HTMLElement; @@ -35,16 +35,19 @@ export class DecksListView { contentEl: HTMLElement, startReviewOfDeck: (deck: Deck) => void, ) { + // Init properties this.plugin = plugin; this.settings = settings; this.reviewSequencer = reviewSequencer; this.modalContentEl = contentEl; this.startReviewOfDeck = startReviewOfDeck; + + // Build ui this.init(); } /** - * Initializes all elements in the DeckListView + * Initializes all static elements in the DeckListView */ init(): void { this.view = this.modalContentEl.createDiv(); @@ -66,7 +69,7 @@ export class DecksListView { } /** - * Shows the DeckListView + * Shows the DeckListView & rerenders dynamic elements */ show(): void { this.mode = FlashcardModalMode.DecksList; @@ -93,6 +96,8 @@ export class DecksListView { } } + // -> Header + private _createHeaderStats() { const statistics: DeckStats = this.reviewSequencer.getDeckStats(TopicPath.emptyPath); this.stats.empty(); @@ -102,10 +107,19 @@ export class DecksListView { this._createHeaderStatsContainer(t("DUE_CARDS"), statistics.dueCount, "sr-bg-green"); } - private _createHeaderStatsContainer(statsLable: string, statsNumber: number, statsClass: string): void { + private _createHeaderStatsContainer( + statsLable: string, + statsNumber: number, + statsClass: string, + ): void { const statsContainer = this.stats.createDiv(); statsContainer.ariaLabel = statsLable; - statsContainer.addClasses(["tag-pane-tag-count", "tree-item-flair", "sr-header-stats-count", statsClass]); + statsContainer.addClasses([ + "tag-pane-tag-count", + "tree-item-flair", + "sr-header-stats-count", + statsClass, + ]); const lable = statsContainer.createDiv(); lable.setText(statsLable + ":"); @@ -114,6 +128,8 @@ export class DecksListView { number.setText(statsNumber.toString()); } + // -> Tree content + private _createTree(deck: Deck, container: HTMLElement): void { const deckTree: HTMLElement = container.createDiv("tree-item sr-tree-item-container"); const deckTreeSelf: HTMLElement = deckTree.createDiv( @@ -176,12 +192,27 @@ export class DecksListView { private _createStats(statistics: DeckStats, statsWrapper: HTMLDivElement) { statsWrapper.empty(); - this._createStatsContainer(t("TOTAL_CARDS"), statistics.totalCount, "sr-bg-red", statsWrapper); + this._createStatsContainer( + t("TOTAL_CARDS"), + statistics.totalCount, + "sr-bg-red", + statsWrapper, + ); this._createStatsContainer(t("NEW_CARDS"), statistics.newCount, "sr-bg-blue", statsWrapper); - this._createStatsContainer(t("DUE_CARDS"), statistics.dueCount, "sr-bg-green", statsWrapper); + this._createStatsContainer( + t("DUE_CARDS"), + statistics.dueCount, + "sr-bg-green", + statsWrapper, + ); } - private _createStatsContainer(statsLable: string, statsNumber: number, statsClass: string, statsWrapper: HTMLDivElement): void { + private _createStatsContainer( + statsLable: string, + statsNumber: number, + statsClass: string, + statsWrapper: HTMLDivElement, + ): void { const statsContainer = statsWrapper.createDiv(); statsContainer.ariaLabel = statsLable; @@ -190,7 +221,7 @@ export class DecksListView { "tag-pane-tag-count", "tree-item-flair", "sr-tree-stats-count", - statsClass + statsClass, ]); statsContainer.setText(statsNumber.toString()); diff --git a/src/gui/FlashcardsEditModal.tsx b/src/gui/EditModal.tsx similarity index 74% rename from src/gui/FlashcardsEditModal.tsx rename to src/gui/EditModal.tsx index a176b496..1c16b7de 100644 --- a/src/gui/FlashcardsEditModal.tsx +++ b/src/gui/EditModal.tsx @@ -3,7 +3,7 @@ import { t } from "src/lang/helpers"; // from https://github.com/chhoumann/quickadd/blob/bce0b4cdac44b867854d6233796e3406dfd163c6/src/gui/GenericInputPrompt/GenericInputPrompt.ts#L5 export class FlashcardEditModal extends Modal { - public input: string; + public changedText: string; public waitForClose: Promise; public title: HTMLDivElement; @@ -15,7 +15,7 @@ export class FlashcardEditModal extends Modal { private resolvePromise: (input: string) => void; // eslint-disable-next-line @typescript-eslint/no-explicit-any private rejectPromise: (reason?: any) => void; - private didSubmit = false; + private didSaveChanges = false; private readonly modalText: string; public static Prompt(app: App, placeholder: string): Promise { @@ -27,16 +27,17 @@ export class FlashcardEditModal extends Modal { super(app); this.modalText = existingText; - this.input = existingText; + this.changedText = existingText; this.waitForClose = new Promise((resolve, reject) => { this.resolvePromise = resolve; this.rejectPromise = reject; }); + // Init static elements in ui this.modalEl.addClass("sr-edit-modal"); - this.init(); + this.open(); } @@ -54,49 +55,45 @@ export class FlashcardEditModal extends Modal { this.textArea = this.contentEl.createEl("textarea"); this.textArea.addClass("sr-input"); this.textArea.setText(this.modalText ?? ""); - this.textArea.addEventListener("keydown", this.submitEnterCallback); + this.textArea.addEventListener("keydown", this.saveOnEnterCallback); - this.createResponse(this.contentEl); + this._createResponse(this.contentEl); } - private _createResponseButton( - container: HTMLElement, - text: string, - colorClass: string, - callback: (evt: MouseEvent) => void, - ) { - const button = container.createEl("button"); - button.addClasses(["sr-response-button", colorClass]); - button.setText(text); - button.addEventListener("click", callback); + /** + * Opens the EditModal + */ + onOpen() { + super.onOpen(); + + this.textArea.focus(); } - private createResponse(mainContentContainer: HTMLElement) { - const response: HTMLDivElement = mainContentContainer.createDiv(); - response.addClass("sr-response"); - this._createResponseButton(response, t("CANCEL"), "sr-bg-red", this.cancelClickCallback); - this._createResponseButton(response, "", "sr-spacer", () => { }); - this._createResponseButton( - response, - t("SAVE"), - "sr-bg-green", - this.submitClickCallback, - ); + /** + * Closes the EditModal + */ + onClose() { + super.onClose(); + this.resolveInput(); + this.removeInputListener(); } - private submitClickCallback = (_: MouseEvent) => this.submit(); + // -> Functions & helpers + + private saveClickCallback = (_: MouseEvent) => this.save(); + private cancelClickCallback = (_: MouseEvent) => this.cancel(); - private submitEnterCallback = (evt: KeyboardEvent) => { + private saveOnEnterCallback = (evt: KeyboardEvent) => { if ((evt.ctrlKey || evt.metaKey) && evt.key === "Enter") { evt.preventDefault(); - this.submit(); + this.save(); } }; - private submit() { - this.didSubmit = true; - this.input = this.textArea.value; + private save() { + this.didSaveChanges = true; + this.changedText = this.textArea.value; this.close(); } @@ -104,24 +101,34 @@ export class FlashcardEditModal extends Modal { this.close(); } - onOpen() { - super.onOpen(); - - this.textArea.focus(); + private resolveInput() { + if (!this.didSaveChanges) this.rejectPromise(t("NO_INPUT")); + else this.resolvePromise(this.changedText); } - onClose() { - super.onClose(); - this.resolveInput(); - this.removeInputListener(); + private removeInputListener() { + this.textArea.removeEventListener("keydown", this.saveOnEnterCallback); } - private resolveInput() { - if (!this.didSubmit) this.rejectPromise(t("NO_INPUT")); - else this.resolvePromise(this.input); + // -> Response section + + private _createResponseButton( + container: HTMLElement, + text: string, + colorClass: string, + callback: (evt: MouseEvent) => void, + ) { + const button = container.createEl("button"); + button.addClasses(["sr-response-button", colorClass]); + button.setText(text); + button.addEventListener("click", callback); } - private removeInputListener() { - this.textArea.removeEventListener("keydown", this.submitEnterCallback); + private _createResponse(mainContentContainer: HTMLElement) { + const response: HTMLDivElement = mainContentContainer.createDiv(); + response.addClass("sr-response"); + this._createResponseButton(response, t("CANCEL"), "sr-bg-red", this.cancelClickCallback); + this._createResponseButton(response, "", "sr-spacer", () => {}); + this._createResponseButton(response, t("SAVE"), "sr-bg-green", this.saveClickCallback); } } diff --git a/src/gui/FlashcardModal.tsx b/src/gui/FlashcardModal.tsx index e58dbbd1..53317f56 100644 --- a/src/gui/FlashcardModal.tsx +++ b/src/gui/FlashcardModal.tsx @@ -11,8 +11,8 @@ import { FlashcardReviewMode, IFlashcardReviewSequencer as IFlashcardReviewSequencer, } from "src/FlashcardReviewSequencer"; -import { FlashcardEditModal } from "./FlashcardsEditModal"; -import { DecksListView } from "./DecksListView"; +import { FlashcardEditModal } from "./EditModal"; +import { DeckListView } from "./DeckListView"; import { FlashcardReviewView } from "./FlashcardReviewView"; export enum FlashcardModalMode { @@ -28,7 +28,7 @@ export class FlashcardModal extends Modal { private reviewSequencer: IFlashcardReviewSequencer; private settings: SRSettings; private reviewMode: FlashcardReviewMode; - private deckView: DecksListView; + private deckView: DeckListView; private flashcardView: FlashcardReviewView; constructor( @@ -40,11 +40,13 @@ export class FlashcardModal extends Modal { ) { super(app); + // Init properties this.plugin = plugin; this.settings = settings; this.reviewSequencer = reviewSequencer; this.reviewMode = reviewMode; + // Setup base containers this.modalEl.style.height = this.settings.flashcardHeightPercentage + "%"; this.modalEl.style.width = this.settings.flashcardWidthPercentage + "%"; this.modalEl.addClass("sr-modal"); @@ -54,12 +56,13 @@ export class FlashcardModal extends Modal { this.contentEl.style.display = "block"; } - this.deckView = new DecksListView( + // Init static elements in views + this.deckView = new DeckListView( this.plugin, this.settings, this.reviewSequencer, this.contentEl, - this.startReviewOfDeck.bind(this), + this._startReviewOfDeck.bind(this), ); this.flashcardView = new FlashcardReviewView( @@ -69,47 +72,49 @@ export class FlashcardModal extends Modal { this.reviewSequencer, this.reviewMode, this.contentEl, - this.showDecksList.bind(this), - this.doEditQuestionText.bind(this), + this._showDecksList.bind(this), + this._doEditQuestionText.bind(this), ); } onOpen(): void { - this.showDecksList(); + this._showDecksList(); } onClose(): void { + this.deckView.hide(); + this.flashcardView.hide(); this.mode = FlashcardModalMode.Closed; } - showDecksList(): void { - this.hideFlashcard(); + private _showDecksList(): void { + this._hideFlashcard(); this.deckView.show(); } - hideDecksList(): void { + private _hideDecksList(): void { this.deckView.hide(); } - showFlashcard(): void { - this.hideDecksList(); + private _showFlashcard(): void { + this._hideDecksList(); this.flashcardView.show(); } - hideFlashcard(): void { + private _hideFlashcard(): void { this.flashcardView.hide(); } - startReviewOfDeck(deck: Deck) { + private _startReviewOfDeck(deck: Deck) { this.reviewSequencer.setCurrentDeck(deck.getTopicPath()); if (this.reviewSequencer.hasCurrentCard) { - this.showFlashcard(); + this._showFlashcard(); } else { - this.showDecksList(); + this._showDecksList(); } } - async doEditQuestionText(): Promise { + private async _doEditQuestionText(): Promise { const currentQ: Question = this.reviewSequencer.currentQuestion; // Just the question/answer text; without any preceding topic tag diff --git a/src/gui/FlashcardReviewView.tsx b/src/gui/FlashcardReviewView.tsx index c08f6bb4..e8358d9b 100644 --- a/src/gui/FlashcardReviewView.tsx +++ b/src/gui/FlashcardReviewView.tsx @@ -21,6 +21,7 @@ export class FlashcardReviewView { public app: App; public plugin: SRPlugin; public modalContentEl: HTMLElement; + public mode: FlashcardModalMode; public view: HTMLDivElement; @@ -43,7 +44,6 @@ export class FlashcardReviewView { public easyButton: HTMLButtonElement; public answerButton: HTMLButtonElement; - public mode: FlashcardModalMode; private reviewSequencer: IFlashcardReviewSequencer; private settings: SRSettings; private reviewMode: FlashcardReviewMode; @@ -60,6 +60,7 @@ export class FlashcardReviewView { backClickHandler: () => void, editClickHandler: () => void, ) { + // Init properties this.app = app; this.plugin = plugin; this.settings = settings; @@ -67,16 +68,14 @@ export class FlashcardReviewView { this.reviewMode = reviewMode; this.backClickHandler = backClickHandler; this.editClickHandler = editClickHandler; - this.modalContentEl = contentEl; - document.addEventListener("keydown", this._keydownHandler.bind(this)); - + // Build ui this.init(); } /** - * Initializes all Elements in the FlashcardView + * Initializes all static elements in the FlashcardView */ init() { this.view = this.modalContentEl.createDiv(); @@ -93,7 +92,7 @@ export class FlashcardReviewView { this.controls = this.header.createDiv(); this.controls.addClass("sr-controls"); - this._createControls(); + this._createCardControls(); if (this.settings.showContextInCards) { this.context = this.view.createDiv(); @@ -110,23 +109,25 @@ export class FlashcardReviewView { } /** - * Shows the FlashcardView + * Shows the FlashcardView & rerenders all dynamic elements */ async show() { this.mode = FlashcardModalMode.Front; const deck: Deck = this.reviewSequencer.currentDeck; + // Setup title this._setTitle(deck); this.resetButton.disabled = true; + // Setup context if (this.settings.showContextInCards) { this.context.setText( this._formatQuestionContextText(this._currentQuestion.questionContext), ); } + // Setup card content this.content.empty(); - const wrapper: RenderMarkdownWrapper = new RenderMarkdownWrapper( this.app, this.plugin, @@ -134,10 +135,13 @@ export class FlashcardReviewView { ); await wrapper.renderMarkdownWrapper(this._currentCard.front, this.content); + // Setup response buttons this._resetResponseButtons(); + // Prevents the following code, from running if this show is just a redraw and not an unhide if (this.view.hasClass("sr-is-hidden")) { this.view.removeClass("sr-is-hidden"); + document.addEventListener("keydown", this._keydownHandler.bind(this)); } } @@ -145,123 +149,18 @@ export class FlashcardReviewView { * Hides the FlashcardView */ hide() { + // Prevents the following code, from running if this was executed multiple times after one another if (!this.view.hasClass("sr-is-hidden")) { this.view.addClass("sr-is-hidden"); + document.removeEventListener("keydown", this._keydownHandler.bind(this)); } } - private _createBackButton() { - this.backButton = this.header.createEl("button"); - this.backButton.addClasses(["sr-button", "sr-back-button"]); - setIcon(this.backButton, "arrow-left"); - this.backButton.setAttribute("aria-label", t("BACK")); - this.backButton.addEventListener("click", () => { - /* this.plugin.data.historyDeck = ""; */ - this.backClickHandler(); - }); - } - - private _setTitle(deck: Deck) { - this.title.setText(`${deck.deckName}: ${deck.getCardCount(CardListType.All, true)}`); - } - - private _createControls() { - this._createEditButton(); - this._createResetButton(); - this._createCardInfoButton(); - this._createSkipButton(); - } - - private _createEditButton() { - this.editButton = this.controls.createEl("button"); - this.editButton.addClasses(["sr-button", "sr-edit-button"]); - setIcon(this.editButton, "edit"); - this.editButton.setAttribute("aria-label", t("EDIT_CARD")); - this.editButton.addEventListener("click", async () => { - this.editClickHandler(); - }); - } - - private _createResetButton() { - this.resetButton = this.controls.createEl("button"); - this.resetButton.addClasses(["sr-button", "sr-reset-button"]); - setIcon(this.resetButton, "refresh-cw"); - this.resetButton.setAttribute("aria-label", t("RESET_CARD_PROGRESS")); - this.resetButton.addEventListener("click", () => { - this._processReview(ReviewResponse.Reset); - }); - } - - private _createCardInfoButton() { - this.infoButton = this.controls.createEl("button"); - this.infoButton.addClasses(["sr-button", "sr-info-button"]); - setIcon(this.infoButton, "info"); - this.infoButton.setAttribute("aria-label", "View Card Info"); - this.infoButton.addEventListener("click", async () => { - this._displayCurrentCardInfoNotice(); - }); - } - - private _createSkipButton() { - this.skipButton = this.controls.createEl("button"); - this.skipButton.addClasses(["sr-button", "sr-skip-button"]); - setIcon(this.skipButton, "chevrons-right"); - this.skipButton.setAttribute("aria-label", t("SKIP")); - this.skipButton.addEventListener("click", () => { - this._skipCurrentCard(); - }); - } - - private _createResponseButtons() { - this._createShowAnswerButton(); - this._createHardButton(); - this._createGoodButton(); - this._createEasyButton(); - } - - private _createShowAnswerButton() { - this.answerButton = this.response.createEl("button"); - this.answerButton.addClasses(["sr-response-button", "sr-show-answer-button", "sr-bg-blue"]); - this.answerButton.setText(t("SHOW_ANSWER")); - this.answerButton.addEventListener("click", () => { - this._showAnswer(); - }); - } - - private _createHardButton() { - this.hardButton = this.response.createEl("button"); - this.hardButton.addClasses(["sr-response-button", "sr-hard-button", "sr-bg-red", "sr-is-hidden"]); - this.hardButton.setText(this.settings.flashcardHardText); - this.hardButton.addEventListener("click", () => { - this._processReview(ReviewResponse.Hard); - }); - } - - private _createGoodButton() { - this.goodButton = this.response.createEl("button"); - this.goodButton.addClasses(["sr-response-button", "sr-good-button", "sr-bg-blue", "sr-is-hidden"]); - this.goodButton.setText(this.settings.flashcardGoodText); - this.goodButton.addEventListener("click", () => { - this._processReview(ReviewResponse.Good); - }); - } - - private _createEasyButton() { - this.easyButton = this.response.createEl("button"); - this.easyButton.addClasses(["sr-response-button", "sr-hard-button", "sr-bg-green", "sr-is-hidden"]); - this.easyButton.setText(this.settings.flashcardEasyText); - this.easyButton.addEventListener("click", () => { - this._processReview(ReviewResponse.Easy); - }); - } + // -> Functions & helpers private _keydownHandler(e: KeyboardEvent): void { - // Checks if the input textbox is in focus before processing keyboard shortcuts. - if ( - document.activeElement.nodeName === "TEXTAREA" || - this.mode === FlashcardModalMode.DecksList || - this.mode === FlashcardModalMode.Closed - ) { + // Prevents any input, if the edit modal is open + if (document.activeElement.nodeName === "TEXTAREA") { return; } @@ -331,20 +230,15 @@ export class FlashcardReviewView { private _displayCurrentCardInfoNotice() { const schedule = this._currentCard.scheduleInfo; + const currentEaseStr = t("CURRENT_EASE_HELP_TEXT") + (schedule?.ease ?? t("NEW")); const currentIntervalStr = t("CURRENT_INTERVAL_HELP_TEXT") + textInterval(schedule?.interval, false); const generatedFromStr = t("CARD_GENERATED_FROM", { notePath: this._currentQuestion.note.filePath, }); - new Notice(currentEaseStr + "\n" + currentIntervalStr + "\n" + generatedFromStr); - } - private _resetResponseButtons() { - this.answerButton.removeClass("sr-is-hidden"); - this.hardButton.addClass("sr-is-hidden"); - this.goodButton.addClass("sr-is-hidden"); - this.easyButton.addClass("sr-is-hidden"); + new Notice(currentEaseStr + "\n" + currentIntervalStr + "\n" + generatedFromStr); } private get _currentCard(): Card { @@ -366,6 +260,7 @@ export class FlashcardReviewView { this.resetButton.disabled = false; } + // Show answer text if (this._currentQuestion.questionType !== CardType.Cloze) { const hr: HTMLElement = document.createElement("hr"); hr.addClass("sr-card-divide"); @@ -381,6 +276,7 @@ export class FlashcardReviewView { ); wrapper.renderMarkdownWrapper(this._currentCard.back, this.content); + // Show response buttons this.answerButton.addClass("sr-is-hidden"); this.hardButton.removeClass("sr-is-hidden"); this.easyButton.removeClass("sr-is-hidden"); @@ -435,6 +331,140 @@ export class FlashcardReviewView { return result + separator + "..."; } + // -> Header + + private _createBackButton() { + this.backButton = this.header.createEl("button"); + this.backButton.addClasses(["sr-button", "sr-back-button"]); + setIcon(this.backButton, "arrow-left"); + this.backButton.setAttribute("aria-label", t("BACK")); + this.backButton.addEventListener("click", () => { + /* this.plugin.data.historyDeck = ""; */ + this.backClickHandler(); + }); + } + + private _setTitle(deck: Deck) { + this.title.setText(`${deck.deckName}: ${deck.getCardCount(CardListType.All, true)}`); + } + + // -> Controls + + private _createCardControls() { + this._createEditButton(); + this._createResetButton(); + this._createCardInfoButton(); + this._createSkipButton(); + } + + private _createEditButton() { + this.editButton = this.controls.createEl("button"); + this.editButton.addClasses(["sr-button", "sr-edit-button"]); + setIcon(this.editButton, "edit"); + this.editButton.setAttribute("aria-label", t("EDIT_CARD")); + this.editButton.addEventListener("click", async () => { + this.editClickHandler(); + }); + } + + private _createResetButton() { + this.resetButton = this.controls.createEl("button"); + this.resetButton.addClasses(["sr-button", "sr-reset-button"]); + setIcon(this.resetButton, "refresh-cw"); + this.resetButton.setAttribute("aria-label", t("RESET_CARD_PROGRESS")); + this.resetButton.addEventListener("click", () => { + this._processReview(ReviewResponse.Reset); + }); + } + + private _createCardInfoButton() { + this.infoButton = this.controls.createEl("button"); + this.infoButton.addClasses(["sr-button", "sr-info-button"]); + setIcon(this.infoButton, "info"); + this.infoButton.setAttribute("aria-label", "View Card Info"); + this.infoButton.addEventListener("click", async () => { + this._displayCurrentCardInfoNotice(); + }); + } + + private _createSkipButton() { + this.skipButton = this.controls.createEl("button"); + this.skipButton.addClasses(["sr-button", "sr-skip-button"]); + setIcon(this.skipButton, "chevrons-right"); + this.skipButton.setAttribute("aria-label", t("SKIP")); + this.skipButton.addEventListener("click", () => { + this._skipCurrentCard(); + }); + } + + // -> Response + + private _createResponseButtons() { + this._createShowAnswerButton(); + this._createHardButton(); + this._createGoodButton(); + this._createEasyButton(); + } + + private _resetResponseButtons() { + // Sets all buttons in to their default state + this.answerButton.removeClass("sr-is-hidden"); + this.hardButton.addClass("sr-is-hidden"); + this.goodButton.addClass("sr-is-hidden"); + this.easyButton.addClass("sr-is-hidden"); + } + + private _createShowAnswerButton() { + this.answerButton = this.response.createEl("button"); + this.answerButton.addClasses(["sr-response-button", "sr-show-answer-button", "sr-bg-blue"]); + this.answerButton.setText(t("SHOW_ANSWER")); + this.answerButton.addEventListener("click", () => { + this._showAnswer(); + }); + } + + private _createHardButton() { + this.hardButton = this.response.createEl("button"); + this.hardButton.addClasses([ + "sr-response-button", + "sr-hard-button", + "sr-bg-red", + "sr-is-hidden", + ]); + this.hardButton.setText(this.settings.flashcardHardText); + this.hardButton.addEventListener("click", () => { + this._processReview(ReviewResponse.Hard); + }); + } + + private _createGoodButton() { + this.goodButton = this.response.createEl("button"); + this.goodButton.addClasses([ + "sr-response-button", + "sr-good-button", + "sr-bg-blue", + "sr-is-hidden", + ]); + this.goodButton.setText(this.settings.flashcardGoodText); + this.goodButton.addEventListener("click", () => { + this._processReview(ReviewResponse.Good); + }); + } + + private _createEasyButton() { + this.easyButton = this.response.createEl("button"); + this.easyButton.addClasses([ + "sr-response-button", + "sr-hard-button", + "sr-bg-green", + "sr-is-hidden", + ]); + this.easyButton.setText(this.settings.flashcardEasyText); + this.easyButton.addEventListener("click", () => { + this._processReview(ReviewResponse.Easy); + }); + } + private _setupEaseButton( button: HTMLElement, buttonName: string, diff --git a/src/main.ts b/src/main.ts index 6fbb5e02..f468330d 100644 --- a/src/main.ts +++ b/src/main.ts @@ -486,9 +486,9 @@ export default class SRPlugin extends Plugin { if (this.data.settings.showDebugMessages) { console.log( "SR: " + - t("SYNC_TIME_TAKEN", { - t: Date.now() - now.valueOf(), - }), + t("SYNC_TIME_TAKEN", { + t: Date.now() - now.valueOf(), + }), ); } @@ -647,8 +647,8 @@ export default class SRPlugin extends Plugin { fileText = fileText.replace( SCHEDULING_INFO_REGEX, `---\n${schedulingInfo[1]}sr-due: ${dueString}\n` + - `sr-interval: ${interval}\nsr-ease: ${ease}\n` + - `${schedulingInfo[5]}---`, + `sr-interval: ${interval}\nsr-ease: ${ease}\n` + + `${schedulingInfo[5]}---`, ); } else if (YAML_FRONT_MATTER_REGEX.test(fileText)) { // new note with existing YAML front matter @@ -656,7 +656,7 @@ export default class SRPlugin extends Plugin { fileText = fileText.replace( YAML_FRONT_MATTER_REGEX, `---\n${existingYaml[1]}sr-due: ${dueString}\n` + - `sr-interval: ${interval}\nsr-ease: ${ease}\n---`, + `sr-interval: ${interval}\nsr-ease: ${ease}\n---`, ); } else { fileText = diff --git a/styles.css b/styles.css index ed645986..3d6b0f64 100644 --- a/styles.css +++ b/styles.css @@ -190,7 +190,7 @@ body:not(.native-scrollbars) .sr-modal .modal-close-button { } .sr-edit-modal { - height: 80% + height: 80%; } .sr-edit-view { @@ -200,7 +200,7 @@ body:not(.native-scrollbars) .sr-modal .modal-close-button { flex-direction: column; justify-content: center; align-items: center; - gap: var(--size-4-4) + gap: var(--size-4-4); } .sr-edit-view .sr-input { @@ -249,4 +249,4 @@ body:not(.native-scrollbars) .sr-modal .modal-close-button { .sr-flashcard .sr-content::-webkit-scrollbar { display: none; } -} \ No newline at end of file +} From 8c97e3946b58a48c100264ea1701a2b33c8eb168 Mon Sep 17 00:00:00 2001 From: KyleKlus Date: Mon, 12 Feb 2024 11:16:07 +0100 Subject: [PATCH 18/37] UPDATE: Added modal styles to the edit modal & commented the styles file --- src/gui/EditModal.tsx | 2 +- styles.css | 109 +++++++++++++++++++++++------------------- 2 files changed, 60 insertions(+), 51 deletions(-) diff --git a/src/gui/EditModal.tsx b/src/gui/EditModal.tsx index 1c16b7de..aca530d4 100644 --- a/src/gui/EditModal.tsx +++ b/src/gui/EditModal.tsx @@ -35,7 +35,7 @@ export class FlashcardEditModal extends Modal { }); // Init static elements in ui - this.modalEl.addClass("sr-edit-modal"); + this.modalEl.addClasses(["sr-modal","sr-edit-modal"]); this.init(); this.open(); diff --git a/styles.css b/styles.css index 3d6b0f64..d25c620e 100644 --- a/styles.css +++ b/styles.css @@ -1,3 +1,4 @@ +/* -> General styling */ .sr-modal .modal-close-button { z-index: 21; } @@ -14,6 +15,56 @@ body:not(.native-scrollbars) .sr-modal .modal-close-button { display: none !important; } +.sr-centered { + display: flex; + justify-content: center; + align-items: center; + flex-direction: column; +} + +.sr-deck-list, +.sr-flashcard, +.sr-edit-view { + display: flex; + flex-direction: column; + width: 100%; + height: 100%; +} + +.sr-header { + display: flex; + flex-direction: column; + justify-content: center; + align-items: center; + width: 100%; + border-bottom: 1px solid var(--hr-color); +} + +.sr-title { + font-size: var(--font-ui-large); + font-weight: var(--font-semibold); + text-align: center; + line-height: var(--line-height-tight); +} + +.sr-response { + display: flex; + width: 100%; + margin-top: var(--size-4-4); + gap: var(--size-4-4); +} + +.sr-response-button { + height: 48px; + flex-grow: 1; + margin: auto; + line-height: 48px; + text-align: center; + cursor: pointer; + border-radius: 4px; + user-select: text; +} + .sr-bg-blue, .sr-bg-green, .sr-bg-red { @@ -47,23 +98,7 @@ body:not(.native-scrollbars) .sr-modal .modal-close-button { background-color: hsl(14, 100%, 58%) !important; } -.sr-deck-list, -.sr-flashcard, -.sr-edit-view { - display: flex; - flex-direction: column; - width: 100%; - height: 100%; -} - -.sr-header { - display: flex; - flex-direction: column; - justify-content: center; - align-items: center; - width: 100%; - border-bottom: 1px solid var(--hr-color); -} +/* -> DeckListView */ .sr-deck-list .sr-header { gap: 8px; @@ -71,13 +106,6 @@ body:not(.native-scrollbars) .sr-modal .modal-close-button { margin-bottom: 24px; } -.sr-title { - font-size: var(--font-ui-large); - font-weight: var(--font-semibold); - text-align: center; - line-height: var(--line-height-tight); -} - .sr-deck-list .sr-header-stats-container { display: flex; gap: 8px; @@ -118,6 +146,8 @@ body:not(.native-scrollbars) .sr-modal .modal-close-button { color: #ffffff !important; } +/* -> FlashcardReviewView */ + .sr-flashcard .sr-header { position: relative; gap: 8px; @@ -171,23 +201,7 @@ body:not(.native-scrollbars) .sr-modal .modal-close-button { border-top-style: dashed; } -.sr-response { - display: flex; - width: 100%; - margin-top: var(--size-4-4); - gap: var(--size-4-4); -} - -.sr-response-button { - height: 48px; - flex-grow: 1; - margin: auto; - line-height: 48px; - text-align: center; - cursor: pointer; - border-radius: 4px; - user-select: text; -} +/* -> EditModal */ .sr-edit-modal { height: 80%; @@ -225,20 +239,15 @@ body:not(.native-scrollbars) .sr-modal .modal-close-button { cursor: default; } -/* OLD stuff */ - -.sr-centered { - display: flex; - justify-content: center; - align-items: center; - flex-direction: column; -} +/* -> Statistics */ #sr-chart-period { appearance: menulist; border-right: 8px solid transparent; } +/* -> Responsive styles */ + @media only screen and (max-width: 600px) { .sr-modal-content { width: 98% !important; @@ -249,4 +258,4 @@ body:not(.native-scrollbars) .sr-modal .modal-close-button { .sr-flashcard .sr-content::-webkit-scrollbar { display: none; } -} +} \ No newline at end of file From 24d48381af1dfc43d3d5e2bc36b10eaad00053e1 Mon Sep 17 00:00:00 2001 From: KyleKlus Date: Mon, 12 Feb 2024 11:22:36 +0100 Subject: [PATCH 19/37] UPDATE: Documented code changes --- docs/changelog.md | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/docs/changelog.md b/docs/changelog.md index b555a1b2..96a9b7b1 100644 --- a/docs/changelog.md +++ b/docs/changelog.md @@ -12,7 +12,7 @@ Generated by [`auto-changelog`](https://github.com/CookPete/auto-changelog). - Fixes bug #815 HTML review comment deactivates block identifier https://github.com/st3v3nmw/obsidian-spaced-repetition/issues/815 -##### Changed +#### [Unreleased] - Improved how spacing between the buttons was done - Centered the button groups, which wheren't centered @@ -20,6 +20,15 @@ Generated by [`auto-changelog`](https://github.com/CookPete/auto-changelog). - Refactored each view into it's own file, to reduce clutter and having a monolithic file - Fixed keydown handler with a proper event handler and a switch +#### [Unreleased] + +- Improved view switching, such that less redraws are needed +- Improved DeckListView +- Improved FlashcardReviewView +- Improved EditModal +- Added a bunch of classes for styling +- Renamed gui files such that they follow a uniform naming convention + #### [1.11.1](https://github.com/st3v3nmw/obsidian-spaced-repetition/compare/1.11.0...1.11.1) - chore: fix README to point to new project board [`#848`](https://github.com/st3v3nmw/obsidian-spaced-repetition/pull/848) From a5387e9425d7aa4250f59faf8e840436a2de6223 Mon Sep 17 00:00:00 2001 From: KyleKlus Date: Mon, 12 Feb 2024 13:15:49 +0100 Subject: [PATCH 20/37] FIX: Fixed that the overflow behavior cause the buttons to move --- styles.css | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/styles.css b/styles.css index d25c620e..841a563e 100644 --- a/styles.css +++ b/styles.css @@ -9,6 +9,7 @@ body:not(.native-scrollbars) .sr-modal .modal-close-button { .sr-modal-content { position: relative; + overflow: hidden; } .sr-is-hidden { @@ -47,6 +48,10 @@ body:not(.native-scrollbars) .sr-modal .modal-close-button { line-height: var(--line-height-tight); } +.sr-content { + overflow-y: auto; +} + .sr-response { display: flex; width: 100%; From 7456b38167b0bccca257d485c7eb8e0834ba1a08 Mon Sep 17 00:00:00 2001 From: KyleKlus Date: Mon, 12 Feb 2024 13:16:39 +0100 Subject: [PATCH 21/37] UPDATE: formatted with prettier --- src/gui/EditModal.tsx | 2 +- styles.css | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/gui/EditModal.tsx b/src/gui/EditModal.tsx index aca530d4..1feb19d5 100644 --- a/src/gui/EditModal.tsx +++ b/src/gui/EditModal.tsx @@ -35,7 +35,7 @@ export class FlashcardEditModal extends Modal { }); // Init static elements in ui - this.modalEl.addClasses(["sr-modal","sr-edit-modal"]); + this.modalEl.addClasses(["sr-modal", "sr-edit-modal"]); this.init(); this.open(); diff --git a/styles.css b/styles.css index 841a563e..3c7a3154 100644 --- a/styles.css +++ b/styles.css @@ -263,4 +263,4 @@ body:not(.native-scrollbars) .sr-modal .modal-close-button { .sr-flashcard .sr-content::-webkit-scrollbar { display: none; } -} \ No newline at end of file +} From 985d3d72b14c02e14a4dc2bdbd11a76a9eb7cb31 Mon Sep 17 00:00:00 2001 From: KyleKlus Date: Mon, 12 Feb 2024 14:23:15 +0100 Subject: [PATCH 22/37] FIX: Fixed mobile view --- docs/changelog.md | 1 + src/gui/FlashcardModal.tsx | 6 +++--- styles.css | 28 +++++++++++++--------------- 3 files changed, 17 insertions(+), 18 deletions(-) diff --git a/docs/changelog.md b/docs/changelog.md index 96a9b7b1..e6ced3b8 100644 --- a/docs/changelog.md +++ b/docs/changelog.md @@ -28,6 +28,7 @@ Generated by [`auto-changelog`](https://github.com/CookPete/auto-changelog). - Improved EditModal - Added a bunch of classes for styling - Renamed gui files such that they follow a uniform naming convention +- Improved mobile view #### [1.11.1](https://github.com/st3v3nmw/obsidian-spaced-repetition/compare/1.11.0...1.11.1) diff --git a/src/gui/FlashcardModal.tsx b/src/gui/FlashcardModal.tsx index 53317f56..5810e01f 100644 --- a/src/gui/FlashcardModal.tsx +++ b/src/gui/FlashcardModal.tsx @@ -52,9 +52,9 @@ export class FlashcardModal extends Modal { this.modalEl.addClass("sr-modal"); this.contentEl.addClass("sr-modal-content"); - if (Platform.isMobile) { - this.contentEl.style.display = "block"; - } + // if (Platform.isMobile) { + // this.contentEl.style.display = "block"; + // } // Init static elements in views this.deckView = new DeckListView( diff --git a/styles.css b/styles.css index 3c7a3154..3063f762 100644 --- a/styles.css +++ b/styles.css @@ -1,4 +1,15 @@ /* -> General styling */ +.is-phone .sr-modal { + --top-space: calc(var(--safe-area-inset-top) + var(--header-height) + var(--size-4-2)); + width: 100vw !important; + height: calc(100vh - var(--top-space)) !important; + margin-top: var(--top-space); +} + +.sr-modal .modal-title{ + display: none; +} + .sr-modal .modal-close-button { z-index: 21; } @@ -113,6 +124,7 @@ body:not(.native-scrollbars) .sr-modal .modal-close-button { .sr-deck-list .sr-header-stats-container { display: flex; + flex-wrap: wrap; gap: 8px; } @@ -249,18 +261,4 @@ body:not(.native-scrollbars) .sr-modal .modal-close-button { #sr-chart-period { appearance: menulist; border-right: 8px solid transparent; -} - -/* -> Responsive styles */ - -@media only screen and (max-width: 600px) { - .sr-modal-content { - width: 98% !important; - } - - .sr-modal-content::-webkit-scrollbar, - .sr-deck-list .sr-content::-webkit-scrollbar, - .sr-flashcard .sr-content::-webkit-scrollbar { - display: none; - } -} +} \ No newline at end of file From 9421db069d7ecbd888a6ab2e8808cb083d78fd8e Mon Sep 17 00:00:00 2001 From: KyleKlus Date: Mon, 12 Feb 2024 15:25:13 +0100 Subject: [PATCH 23/37] FIX: Fixed that mobile view wasn't spanning the whole screen, like it used to do --- src/gui/flashcard-modal.tsx | 1 + styles.css | 11 +++++++++++ 2 files changed, 12 insertions(+) diff --git a/src/gui/flashcard-modal.tsx b/src/gui/flashcard-modal.tsx index 3dd1ad74..e7883714 100644 --- a/src/gui/flashcard-modal.tsx +++ b/src/gui/flashcard-modal.tsx @@ -64,6 +64,7 @@ export class FlashcardModal extends Modal { this.modalEl.style.height = this.settings.flashcardHeightPercentage + "%"; this.modalEl.style.width = this.settings.flashcardWidthPercentage + "%"; + this.modalEl.addClass("sr-modal"); } onOpen(): void { diff --git a/styles.css b/styles.css index 60c8ad51..984e78a9 100644 --- a/styles.css +++ b/styles.css @@ -1,3 +1,14 @@ +.is-phone .sr-modal { + --top-space: calc(var(--safe-area-inset-top) + var(--header-height) + var(--size-4-2)); + width: 100vw !important; + height: calc(100vh - var(--top-space)) !important; + margin-top: var(--top-space); +} + +.sr-modal .modal-title{ + display: none; +} + .sr-flashcard-menu { width: 100%; display: flex; From e56fa6d11498c621b3b8ab81ce52ec213159829b Mon Sep 17 00:00:00 2001 From: KyleKlus Date: Mon, 12 Feb 2024 15:31:58 +0100 Subject: [PATCH 24/37] UPDATE: Formatted with prettier --- styles.css | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/styles.css b/styles.css index 984e78a9..afaf6eaa 100644 --- a/styles.css +++ b/styles.css @@ -5,7 +5,7 @@ margin-top: var(--top-space); } -.sr-modal .modal-title{ +.sr-modal .modal-title { display: none; } From 73339204e3aca64516177df334214cc54e22a2a3 Mon Sep 17 00:00:00 2001 From: KyleKlus Date: Sun, 18 Feb 2024 11:47:08 +0100 Subject: [PATCH 25/37] UPDATE: Shortened changelog as requested in the review --- docs/changelog.md | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) diff --git a/docs/changelog.md b/docs/changelog.md index b555a1b2..fe12b3f2 100644 --- a/docs/changelog.md +++ b/docs/changelog.md @@ -12,13 +12,9 @@ Generated by [`auto-changelog`](https://github.com/CookPete/auto-changelog). - Fixes bug #815 HTML review comment deactivates block identifier https://github.com/st3v3nmw/obsidian-spaced-repetition/issues/815 -##### Changed +##### [Unreleased] -- Improved how spacing between the buttons was done -- Centered the button groups, which wheren't centered -- Fixed a hack in the response of the cram card mode -- Refactored each view into it's own file, to reduce clutter and having a monolithic file -- Fixed keydown handler with a proper event handler and a switch +- Gui refactored into separate views & rewrite of keydown handler into event handler [#873](https://github.com/st3v3nmw/obsidian-spaced-repetition/pull/873) #### [1.11.1](https://github.com/st3v3nmw/obsidian-spaced-repetition/compare/1.11.0...1.11.1) From 9cde10c4fdd95966d44d8604ede450e1253ef5f7 Mon Sep 17 00:00:00 2001 From: KyleKlus Date: Sun, 18 Feb 2024 11:55:01 +0100 Subject: [PATCH 26/37] FIX: Fixed unused variables warning --- src/gui/DecksListView.tsx | 4 ---- src/gui/flashcard-modal.tsx | 26 +++----------------------- 2 files changed, 3 insertions(+), 27 deletions(-) diff --git a/src/gui/DecksListView.tsx b/src/gui/DecksListView.tsx index bf1a34dd..3656aaa0 100644 --- a/src/gui/DecksListView.tsx +++ b/src/gui/DecksListView.tsx @@ -12,11 +12,9 @@ import { IFlashcardReviewSequencer as IFlashcardReviewSequencer, } from "src/FlashcardReviewSequencer"; import { TopicPath } from "src/TopicPath"; -import { FlashcardModalMode } from "./flashcard-modal"; export class DecksListView { public plugin: SRPlugin; - public mode: FlashcardModalMode; public titleEl: HTMLElement; public contentEl: HTMLElement; private reviewSequencer: IFlashcardReviewSequencer; @@ -53,8 +51,6 @@ export class DecksListView { * Shows the DeckListView */ show(): void { - this.mode = FlashcardModalMode.DecksList; - const stats: DeckStats = this.reviewSequencer.getDeckStats(TopicPath.emptyPath); this.titleEl.setText(t("DECKS")); diff --git a/src/gui/flashcard-modal.tsx b/src/gui/flashcard-modal.tsx index e7883714..37571719 100644 --- a/src/gui/flashcard-modal.tsx +++ b/src/gui/flashcard-modal.tsx @@ -1,25 +1,16 @@ -import { Modal, App, Notice, Platform, setIcon } from "obsidian"; +import { Modal, App } from "obsidian"; // eslint-disable-next-line @typescript-eslint/no-unused-vars import h from "vhtml"; import type SRPlugin from "src/main"; import { SRSettings } from "src/settings"; -import { textInterval, ReviewResponse } from "src/scheduling"; -import { COLLAPSE_ICON } from "src/constants"; -import { t } from "src/lang/helpers"; -import { Card } from "../Card"; -import { CardListType, Deck } from "../Deck"; -import { CardType, Question } from "../Question"; +import { Deck } from "../Deck"; +import { Question } from "../Question"; import { - DeckStats, FlashcardReviewMode, IFlashcardReviewSequencer as IFlashcardReviewSequencer, } from "src/FlashcardReviewSequencer"; import { FlashcardEditModal } from "./flashcards-edit-modal"; -import { Note } from "src/Note"; -import { RenderMarkdownWrapper } from "src/util/RenderMarkdownWrapper"; -import { CardScheduleInfo } from "src/CardSchedule"; -import { TopicPath } from "src/TopicPath"; import { DecksListView } from "./DecksListView"; import { FlashcardReviewView } from "./FlashcardReviewView"; @@ -32,17 +23,6 @@ export enum FlashcardModalMode { export class FlashcardModal extends Modal { public plugin: SRPlugin; - public answerBtn: HTMLElement; - public flashcardView: HTMLElement; - private flashCardMenu: HTMLDivElement; - public hardBtn: HTMLElement; - public goodBtn: HTMLElement; - public easyBtn: HTMLElement; - public nextBtn: HTMLElement; - public responseDiv: HTMLElement; - public resetButton: HTMLButtonElement; - public editButton: HTMLElement; - public contextView: HTMLElement; public mode: FlashcardModalMode; private reviewSequencer: IFlashcardReviewSequencer; private settings: SRSettings; From 970f99e673bca2d2bd372532935e2b0d953aa04e Mon Sep 17 00:00:00 2001 From: KyleKlus Date: Sun, 18 Feb 2024 12:48:31 +0100 Subject: [PATCH 27/37] FIX: Title was hidden for some reason --- styles.css | 4 ---- 1 file changed, 4 deletions(-) diff --git a/styles.css b/styles.css index afaf6eaa..a2e0a6bf 100644 --- a/styles.css +++ b/styles.css @@ -5,10 +5,6 @@ margin-top: var(--top-space); } -.sr-modal .modal-title { - display: none; -} - .sr-flashcard-menu { width: 100%; display: flex; From be1f1f413d786354a76a4618a2445b2c340073fc Mon Sep 17 00:00:00 2001 From: KyleKlus Date: Sun, 18 Feb 2024 12:53:38 +0100 Subject: [PATCH 28/37] UPDATE: Used is-mobile class, instead of is-phone --- styles.css | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/styles.css b/styles.css index a2e0a6bf..b569b986 100644 --- a/styles.css +++ b/styles.css @@ -1,4 +1,4 @@ -.is-phone .sr-modal { +.is-mobile .sr-modal { --top-space: calc(var(--safe-area-inset-top) + var(--header-height) + var(--size-4-2)); width: 100vw !important; height: calc(100vh - var(--top-space)) !important; From 15bb2cc4d0ca10f096108c1a575b259baf0f44d3 Mon Sep 17 00:00:00 2001 From: KyleKlus Date: Sun, 18 Feb 2024 14:43:02 +0100 Subject: [PATCH 29/37] UPDATE: Improved backbutton position --- src/gui/FlashcardModal.tsx | 3 ++- src/gui/FlashcardReviewView.tsx | 11 +++++--- styles.css | 47 +++++++++++++++++++++++---------- 3 files changed, 43 insertions(+), 18 deletions(-) diff --git a/src/gui/FlashcardModal.tsx b/src/gui/FlashcardModal.tsx index 5810e01f..ab8f47a5 100644 --- a/src/gui/FlashcardModal.tsx +++ b/src/gui/FlashcardModal.tsx @@ -49,7 +49,7 @@ export class FlashcardModal extends Modal { // Setup base containers this.modalEl.style.height = this.settings.flashcardHeightPercentage + "%"; this.modalEl.style.width = this.settings.flashcardWidthPercentage + "%"; - this.modalEl.addClass("sr-modal"); + this.modalEl.setAttribute("id", "sr-modal"); this.contentEl.addClass("sr-modal-content"); // if (Platform.isMobile) { @@ -72,6 +72,7 @@ export class FlashcardModal extends Modal { this.reviewSequencer, this.reviewMode, this.contentEl, + this.modalEl, this._showDecksList.bind(this), this._doEditQuestionText.bind(this), ); diff --git a/src/gui/FlashcardReviewView.tsx b/src/gui/FlashcardReviewView.tsx index e8358d9b..77178142 100644 --- a/src/gui/FlashcardReviewView.tsx +++ b/src/gui/FlashcardReviewView.tsx @@ -21,13 +21,14 @@ export class FlashcardReviewView { public app: App; public plugin: SRPlugin; public modalContentEl: HTMLElement; + public modalEl: HTMLElement; public mode: FlashcardModalMode; public view: HTMLDivElement; public header: HTMLDivElement; public title: HTMLDivElement; - public backButton: HTMLButtonElement; + public backButton: HTMLDivElement; public controls: HTMLDivElement; public editButton: HTMLButtonElement; @@ -57,6 +58,7 @@ export class FlashcardReviewView { reviewSequencer: IFlashcardReviewSequencer, reviewMode: FlashcardReviewMode, contentEl: HTMLElement, + modalEl: HTMLElement, backClickHandler: () => void, editClickHandler: () => void, ) { @@ -69,6 +71,7 @@ export class FlashcardReviewView { this.backClickHandler = backClickHandler; this.editClickHandler = editClickHandler; this.modalContentEl = contentEl; + this.modalEl = modalEl; // Build ui this.init(); @@ -141,6 +144,7 @@ export class FlashcardReviewView { // Prevents the following code, from running if this show is just a redraw and not an unhide if (this.view.hasClass("sr-is-hidden")) { this.view.removeClass("sr-is-hidden"); + this.backButton.removeClass("sr-is-hidden"); document.addEventListener("keydown", this._keydownHandler.bind(this)); } } @@ -152,6 +156,7 @@ export class FlashcardReviewView { // Prevents the following code, from running if this was executed multiple times after one another if (!this.view.hasClass("sr-is-hidden")) { this.view.addClass("sr-is-hidden"); + this.backButton.addClass("sr-is-hidden"); document.removeEventListener("keydown", this._keydownHandler.bind(this)); } } @@ -334,8 +339,8 @@ export class FlashcardReviewView { // -> Header private _createBackButton() { - this.backButton = this.header.createEl("button"); - this.backButton.addClasses(["sr-button", "sr-back-button"]); + this.backButton = this.modalEl.createDiv(); + this.backButton.addClasses(["sr-back-button", "sr-is-hidden"]); setIcon(this.backButton, "arrow-left"); this.backButton.setAttribute("aria-label", t("BACK")); this.backButton.addEventListener("click", () => { diff --git a/styles.css b/styles.css index 323acb4f..6e418232 100644 --- a/styles.css +++ b/styles.css @@ -1,20 +1,20 @@ /* -> General styling */ -.is-phone .sr-modal { +.is-phone #sr-modal { --top-space: calc(var(--safe-area-inset-top) + var(--header-height) + var(--size-4-2)); width: 100vw !important; height: calc(100vh - var(--top-space)) !important; margin-top: var(--top-space); } -.sr-modal .modal-title { +#sr-modal .modal-title { display: none; } -.sr-modal .modal-close-button { +#sr-modal .modal-close-button { z-index: 21; } -body:not(.native-scrollbars) .sr-modal .modal-close-button { +body:not(.native-scrollbars) #sr-modal .modal-close-button { top: 12px; } @@ -63,6 +63,34 @@ body:not(.native-scrollbars) .sr-modal .modal-close-button { overflow-y: auto; } +.sr-button { + box-shadow: none !important; + cursor: pointer; +} + +.sr-back-button { + z-index: 21; + cursor: var(--cursor); + position: absolute; + top: 12px; + left: 12px; + font-size: 26px; + line-height: 22px; + height: 26px; + width: 26px; + padding: 0 var(--size-2-2); + border-radius: var(--radius-s); + color: var(--text-muted); + display: flex; + justify-content: center; + align-items: center; +} + +.sr-back-button:hover, +.sr-button:hover { + background-color: var(--background-modifier-hover); +} + .sr-response { display: flex; width: 100%; @@ -171,15 +199,6 @@ body:not(.native-scrollbars) .sr-modal .modal-close-button { padding-bottom: 8px; } -.sr-flashcard .sr-button { - box-shadow: none !important; - cursor: pointer; -} - -.sr-flashcard .sr-button:hover { - background-color: var(--background-modifier-hover); -} - .sr-flashcard .sr-button:disabled { cursor: not-allowed; } @@ -261,4 +280,4 @@ body:not(.native-scrollbars) .sr-modal .modal-close-button { #sr-chart-period { appearance: menulist; border-right: 8px solid transparent; -} +} \ No newline at end of file From 33b035a354953982b112ddae52ab7468608d98ac Mon Sep 17 00:00:00 2001 From: KyleKlus Date: Sun, 18 Feb 2024 14:48:31 +0100 Subject: [PATCH 30/37] UPDATE: Improved context positioning --- styles.css | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/styles.css b/styles.css index 6e418232..81dbfb73 100644 --- a/styles.css +++ b/styles.css @@ -221,6 +221,8 @@ body:not(.native-scrollbars) #sr-modal .modal-close-button { display: block; width: 100%; margin-top: 12px; + margin-bottom: 4px; + margin-left: 8px; } .sr-flashcard .sr-content { @@ -280,4 +282,4 @@ body:not(.native-scrollbars) #sr-modal .modal-close-button { #sr-chart-period { appearance: menulist; border-right: 8px solid transparent; -} \ No newline at end of file +} From cfcbc399f55ad6c4dfbf374704d2245e8cdc7ceb Mon Sep 17 00:00:00 2001 From: KyleKlus Date: Sun, 18 Feb 2024 20:40:07 +0100 Subject: [PATCH 31/37] FIX: Implemented a better close condition --- src/gui/DeckListView.tsx | 7 +++++++ src/gui/FlashcardModal.tsx | 6 ++++-- src/gui/FlashcardReviewView.tsx | 10 +++++++++- 3 files changed, 20 insertions(+), 3 deletions(-) diff --git a/src/gui/DeckListView.tsx b/src/gui/DeckListView.tsx index 87613598..c3141762 100644 --- a/src/gui/DeckListView.tsx +++ b/src/gui/DeckListView.tsx @@ -96,6 +96,13 @@ export class DeckListView { } } + /** + * Closes the DeckListView + */ + close() { + this.hide(); + } + // -> Header private _createHeaderStats() { diff --git a/src/gui/FlashcardModal.tsx b/src/gui/FlashcardModal.tsx index b6477b69..033fdd2c 100644 --- a/src/gui/FlashcardModal.tsx +++ b/src/gui/FlashcardModal.tsx @@ -83,9 +83,11 @@ export class FlashcardModal extends Modal { } onClose(): void { - this.deckView.hide(); - this.flashcardView.hide(); + this.deckView.close(); + this.flashcardView.close(); this.mode = FlashcardModalMode.Closed; + console.log("Close"); + super.close(); } private _showDecksList(): void { diff --git a/src/gui/FlashcardReviewView.tsx b/src/gui/FlashcardReviewView.tsx index 77178142..c3dd3c1d 100644 --- a/src/gui/FlashcardReviewView.tsx +++ b/src/gui/FlashcardReviewView.tsx @@ -161,11 +161,19 @@ export class FlashcardReviewView { } } + /** + * Closes the FlashcardView + */ + close() { + document.removeEventListener("keydown", this._keydownHandler.bind(this)); + this.hide(); + } + // -> Functions & helpers private _keydownHandler(e: KeyboardEvent): void { // Prevents any input, if the edit modal is open - if (document.activeElement.nodeName === "TEXTAREA") { + if (document.activeElement.nodeName === "TEXTAREA" || this.mode === FlashcardModalMode.Closed) { return; } From ad479a1ed35281f829d91867255d1cf76e26266c Mon Sep 17 00:00:00 2001 From: KyleKlus Date: Sun, 18 Feb 2024 20:40:29 +0100 Subject: [PATCH 32/37] FIX: removed debug code --- src/gui/FlashcardModal.tsx | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/gui/FlashcardModal.tsx b/src/gui/FlashcardModal.tsx index 033fdd2c..eba110cb 100644 --- a/src/gui/FlashcardModal.tsx +++ b/src/gui/FlashcardModal.tsx @@ -86,8 +86,6 @@ export class FlashcardModal extends Modal { this.deckView.close(); this.flashcardView.close(); this.mode = FlashcardModalMode.Closed; - console.log("Close"); - super.close(); } private _showDecksList(): void { From e1afbf8c55df528e578442e2e5f9e72806ff524d Mon Sep 17 00:00:00 2001 From: KyleKlus Date: Sun, 18 Feb 2024 22:36:44 +0100 Subject: [PATCH 33/37] FIX: Fixed that the keydown handler did respond, even if the window was closed --- src/gui/FlashcardReviewView.tsx | 24 +++++++++++------------- 1 file changed, 11 insertions(+), 13 deletions(-) diff --git a/src/gui/FlashcardReviewView.tsx b/src/gui/FlashcardReviewView.tsx index c3dd3c1d..91cd2614 100644 --- a/src/gui/FlashcardReviewView.tsx +++ b/src/gui/FlashcardReviewView.tsx @@ -142,11 +142,10 @@ export class FlashcardReviewView { this._resetResponseButtons(); // Prevents the following code, from running if this show is just a redraw and not an unhide - if (this.view.hasClass("sr-is-hidden")) { - this.view.removeClass("sr-is-hidden"); - this.backButton.removeClass("sr-is-hidden"); - document.addEventListener("keydown", this._keydownHandler.bind(this)); - } + if (!this.view.hasClass("sr-is-hidden")) { return; } + this.view.removeClass("sr-is-hidden"); + this.backButton.removeClass("sr-is-hidden"); + document.addEventListener("keydown", this._keydownHandler); } /** @@ -154,24 +153,23 @@ export class FlashcardReviewView { */ hide() { // Prevents the following code, from running if this was executed multiple times after one another - if (!this.view.hasClass("sr-is-hidden")) { - this.view.addClass("sr-is-hidden"); - this.backButton.addClass("sr-is-hidden"); - document.removeEventListener("keydown", this._keydownHandler.bind(this)); - } + if (this.view.hasClass("sr-is-hidden")) { return; } + this.view.addClass("sr-is-hidden"); + this.backButton.addClass("sr-is-hidden"); + document.removeEventListener("keydown", this._keydownHandler); } /** * Closes the FlashcardView */ close() { - document.removeEventListener("keydown", this._keydownHandler.bind(this)); + document.removeEventListener("keydown", this._keydownHandler); this.hide(); } // -> Functions & helpers - private _keydownHandler(e: KeyboardEvent): void { + private _keydownHandler = (e: KeyboardEvent) => { // Prevents any input, if the edit modal is open if (document.activeElement.nodeName === "TEXTAREA" || this.mode === FlashcardModalMode.Closed) { return; @@ -239,7 +237,7 @@ export class FlashcardReviewView { default: break; } - } + }; private _displayCurrentCardInfoNotice() { const schedule = this._currentCard.scheduleInfo; From 600a46ed822ebf7a177ead5572414d01b6aaddfd Mon Sep 17 00:00:00 2001 From: KyleKlus Date: Mon, 11 Mar 2024 18:53:39 +0100 Subject: [PATCH 34/37] UPDATE: Updated changelog & formatted code --- docs/changelog.md | 14 +++----------- src/gui/FlashcardReviewView.tsx | 13 ++++++++++--- 2 files changed, 13 insertions(+), 14 deletions(-) diff --git a/docs/changelog.md b/docs/changelog.md index 93a46c5d..8c551211 100644 --- a/docs/changelog.md +++ b/docs/changelog.md @@ -6,21 +6,13 @@ Generated by [`auto-changelog`](https://github.com/CookPete/auto-changelog). #### [Unreleased] -- Fixes [BUG] Malformed card text during review, when multi-line card has space on Q/A separator line https://github.com/st3v3nmw/obsidian-spaced-repetition/issues/853 - -#### [Unreleased] - -- Fixes bug #815 HTML review comment deactivates block identifier https://github.com/st3v3nmw/obsidian-spaced-repetition/issues/815 - -##### [Unreleased] - -- Gui refactored into separate views & rewrite of keydown handler into event handler [#873](https://github.com/st3v3nmw/obsidian-spaced-repetition/pull/873) -- Make reset button (flashcard review modal) enabled for both new and due cards https://github.com/st3v3nmw/obsidian-spaced-repetition/pull/6 - [FEAT] Command to open notes review panel - #840. [`#846`](https://github.com/st3v3nmw/obsidian-spaced-repetition/pull/846) +- Gui refactored into separate views | rewrite of keydown handler into event handler [`#873`](https://github.com/st3v3nmw/obsidian-spaced-repetition/pull/873) - Make reset button (flashcard review modal) enabled for both new and due cards [`#650`](https://github.com/st3v3nmw/obsidian-spaced-repetition/pull/650) - Support multi-deck cards #495, and multiple decks in a single note #705 [`#834`](https://github.com/st3v3nmw/obsidian-spaced-repetition/pull/834) +- Overhauled ui as described in issue [`#872`](https://github.com/st3v3nmw/obsidian-spaced-repetition/issues/872) -#### [Unreleased] +#### [1.11.2](https://github.com/st3v3nmw/obsidian-spaced-repetition/compare/1.11.1...1.11.2) > 4 March 2024 diff --git a/src/gui/FlashcardReviewView.tsx b/src/gui/FlashcardReviewView.tsx index 91cd2614..80c1f0ce 100644 --- a/src/gui/FlashcardReviewView.tsx +++ b/src/gui/FlashcardReviewView.tsx @@ -142,7 +142,9 @@ export class FlashcardReviewView { this._resetResponseButtons(); // Prevents the following code, from running if this show is just a redraw and not an unhide - if (!this.view.hasClass("sr-is-hidden")) { return; } + if (!this.view.hasClass("sr-is-hidden")) { + return; + } this.view.removeClass("sr-is-hidden"); this.backButton.removeClass("sr-is-hidden"); document.addEventListener("keydown", this._keydownHandler); @@ -153,7 +155,9 @@ export class FlashcardReviewView { */ hide() { // Prevents the following code, from running if this was executed multiple times after one another - if (this.view.hasClass("sr-is-hidden")) { return; } + if (this.view.hasClass("sr-is-hidden")) { + return; + } this.view.addClass("sr-is-hidden"); this.backButton.addClass("sr-is-hidden"); document.removeEventListener("keydown", this._keydownHandler); @@ -171,7 +175,10 @@ export class FlashcardReviewView { private _keydownHandler = (e: KeyboardEvent) => { // Prevents any input, if the edit modal is open - if (document.activeElement.nodeName === "TEXTAREA" || this.mode === FlashcardModalMode.Closed) { + if ( + document.activeElement.nodeName === "TEXTAREA" || + this.mode === FlashcardModalMode.Closed + ) { return; } From 1620e72b9bc23d3a574b32f30ff4fd3c1d51f3bc Mon Sep 17 00:00:00 2001 From: KyleKlus Date: Thu, 14 Mar 2024 21:15:55 +0100 Subject: [PATCH 35/37] FIX: Fixed parts, as requested in review --- manifest.json | 2 +- package.json | 30 +- pnpm-lock.yaml | 1436 +++++++++++++++++++----------------- src/gui/FlashcardModal.tsx | 3 - 4 files changed, 767 insertions(+), 704 deletions(-) diff --git a/manifest.json b/manifest.json index c50c6273..2ff125f9 100644 --- a/manifest.json +++ b/manifest.json @@ -1,7 +1,7 @@ { "id": "obsidian-spaced-repetition", "name": "Spaced Repetition", - "version": "1.11.1", + "version": "1.11.2", "minAppVersion": "0.15.4", "description": "Fight the forgetting curve by reviewing flashcards & entire notes.", "author": "Stephen Mwangi", diff --git a/package.json b/package.json index dc97444d..43f845af 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "obsidian-spaced-repetition", - "version": "1.11.1", + "version": "1.11.2", "description": "Fight the forgetting curve by reviewing flashcards & entire notes.", "main": "main.js", "scripts": { @@ -20,34 +20,34 @@ "author": "Stephen Mwangi", "license": "MIT", "devDependencies": { - "@types/jest": "^29.5.11", - "@types/node": "^20.11.2", + "@types/jest": "^29.5.12", + "@types/node": "^20.11.24", "@types/vhtml": "^2.2.9", - "@typescript-eslint/eslint-plugin": "^6.19.0", - "@typescript-eslint/parser": "^6.19.0", - "@wdio/cli": "^8.27.2", - "@wdio/local-runner": "^8.27.2", - "@wdio/mocha-framework": "^8.27.2", - "@wdio/spec-reporter": "^8.27.2", + "@typescript-eslint/eslint-plugin": "^6.21.0", + "@typescript-eslint/parser": "^6.21.0", + "@wdio/cli": "^8.32.3", + "@wdio/local-runner": "^8.32.3", + "@wdio/mocha-framework": "^8.32.3", + "@wdio/spec-reporter": "^8.32.2", "auto-changelog": "^2.4.0", "builtin-modules": "^3.3.0", "chai": "^4.4.1", - "esbuild": "~0.19.11", - "eslint": "^8.56.0", + "esbuild": "~0.19.12", + "eslint": "^8.57.0", "jest": "^29.7.0", "jest-environment-jsdom": "^29.7.0", "jest-expect-message": "^1.1.3", "moment": "^2.30.1", - "obsidian": "^1.4.11", - "prettier": "^3.2.2", - "ts-jest": "^29.1.1", + "obsidian": "^1.5.7", + "prettier": "^3.2.5", + "ts-jest": "^29.1.2", "tslib": "2.6.1", "typescript": "5.1.6", "vhtml": "^2.2.0", "wdio-chromedriver-service": "^8.1.1" }, "dependencies": { - "chart.js": "^4.4.1", + "chart.js": "^4.4.2", "pagerank.js": "^1.0.2" }, "packageManager": "npm@8.18.0" diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 6f92c722..f08b92ce 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -6,40 +6,40 @@ settings: dependencies: chart.js: - specifier: ^4.4.1 - version: 4.4.1 + specifier: ^4.4.2 + version: 4.4.2 pagerank.js: specifier: ^1.0.2 version: 1.0.2 devDependencies: '@types/jest': - specifier: ^29.5.11 - version: 29.5.11 + specifier: ^29.5.12 + version: 29.5.12 '@types/node': - specifier: ^20.11.2 - version: 20.11.2 + specifier: ^20.11.24 + version: 20.11.24 '@types/vhtml': specifier: ^2.2.9 version: 2.2.9 '@typescript-eslint/eslint-plugin': - specifier: ^6.19.0 - version: 6.19.0(@typescript-eslint/parser@6.19.0)(eslint@8.56.0)(typescript@5.1.6) + specifier: ^6.21.0 + version: 6.21.0(@typescript-eslint/parser@6.21.0)(eslint@8.57.0)(typescript@5.1.6) '@typescript-eslint/parser': - specifier: ^6.19.0 - version: 6.19.0(eslint@8.56.0)(typescript@5.1.6) + specifier: ^6.21.0 + version: 6.21.0(eslint@8.57.0)(typescript@5.1.6) '@wdio/cli': - specifier: ^8.27.2 - version: 8.27.2(typescript@5.1.6) + specifier: ^8.32.3 + version: 8.32.3(typescript@5.1.6) '@wdio/local-runner': - specifier: ^8.27.2 - version: 8.27.2(typescript@5.1.6) + specifier: ^8.32.3 + version: 8.32.3(typescript@5.1.6) '@wdio/mocha-framework': - specifier: ^8.27.2 - version: 8.27.2 + specifier: ^8.32.3 + version: 8.32.3 '@wdio/spec-reporter': - specifier: ^8.27.2 - version: 8.27.2 + specifier: ^8.32.2 + version: 8.32.2 auto-changelog: specifier: ^2.4.0 version: 2.4.0 @@ -50,14 +50,14 @@ devDependencies: specifier: ^4.4.1 version: 4.4.1 esbuild: - specifier: ~0.19.11 - version: 0.19.11 + specifier: ~0.19.12 + version: 0.19.12 eslint: - specifier: ^8.56.0 - version: 8.56.0 + specifier: ^8.57.0 + version: 8.57.0 jest: specifier: ^29.7.0 - version: 29.7.0(@types/node@20.11.2) + version: 29.7.0(@types/node@20.11.24) jest-environment-jsdom: specifier: ^29.7.0 version: 29.7.0 @@ -68,14 +68,14 @@ devDependencies: specifier: ^2.30.1 version: 2.30.1 obsidian: - specifier: ^1.4.11 - version: 1.4.11(@codemirror/state@6.4.0)(@codemirror/view@6.23.0) + specifier: ^1.5.7 + version: 1.5.7(@codemirror/state@6.4.1)(@codemirror/view@6.24.1) prettier: - specifier: ^3.2.2 - version: 3.2.2 + specifier: ^3.2.5 + version: 3.2.5 ts-jest: - specifier: ^29.1.1 - version: 29.1.1(@babel/core@7.23.7)(esbuild@0.19.11)(jest@29.7.0)(typescript@5.1.6) + specifier: ^29.1.2 + version: 29.1.2(@babel/core@7.24.0)(esbuild@0.19.12)(jest@29.7.0)(typescript@5.1.6) tslib: specifier: 2.6.1 version: 2.6.1 @@ -87,7 +87,7 @@ devDependencies: version: 2.2.0 wdio-chromedriver-service: specifier: ^8.1.1 - version: 8.1.1(webdriverio@8.27.2) + version: 8.1.1(webdriverio@8.32.3) packages: @@ -96,12 +96,12 @@ packages: engines: {node: '>=0.10.0'} dev: true - /@ampproject/remapping@2.2.1: - resolution: {integrity: sha512-lFMjJTrFL3j7L9yBxwYfCq2k6qqwHyzuUl/XBnif78PWTJYyL/dfowQHWE3sp6U6ZzqWiiIZnpTMO96zhkjwtg==} + /@ampproject/remapping@2.3.0: + resolution: {integrity: sha512-30iZtAPgz+LTIYoeivqYo853f02jBYSd5uGnGpkFV0M3xOt9aN73erkgYAmZU43x4VfqcnLxW9Kpg3R5LC4YYw==} engines: {node: '>=6.0.0'} dependencies: - '@jridgewell/gen-mapping': 0.3.3 - '@jridgewell/trace-mapping': 0.3.21 + '@jridgewell/gen-mapping': 0.3.5 + '@jridgewell/trace-mapping': 0.3.25 dev: true /@babel/code-frame@7.23.5: @@ -117,20 +117,20 @@ packages: engines: {node: '>=6.9.0'} dev: true - /@babel/core@7.23.7: - resolution: {integrity: sha512-+UpDgowcmqe36d4NwqvKsyPMlOLNGMsfMmQ5WGCu+siCe3t3dfe9njrzGfdN4qq+bcNUt0+Vw6haRxBOycs4dw==} + /@babel/core@7.24.0: + resolution: {integrity: sha512-fQfkg0Gjkza3nf0c7/w6Xf34BW4YvzNfACRLmmb7XRLa6XHdR+K9AlJlxneFfWYf6uhOzuzZVTjF/8KfndZANw==} engines: {node: '>=6.9.0'} dependencies: - '@ampproject/remapping': 2.2.1 + '@ampproject/remapping': 2.3.0 '@babel/code-frame': 7.23.5 '@babel/generator': 7.23.6 '@babel/helper-compilation-targets': 7.23.6 - '@babel/helper-module-transforms': 7.23.3(@babel/core@7.23.7) - '@babel/helpers': 7.23.8 - '@babel/parser': 7.23.6 - '@babel/template': 7.22.15 - '@babel/traverse': 7.23.7 - '@babel/types': 7.23.6 + '@babel/helper-module-transforms': 7.23.3(@babel/core@7.24.0) + '@babel/helpers': 7.24.0 + '@babel/parser': 7.24.0 + '@babel/template': 7.24.0 + '@babel/traverse': 7.24.0 + '@babel/types': 7.24.0 convert-source-map: 2.0.0 debug: 4.3.4(supports-color@8.1.1) gensync: 1.0.0-beta.2 @@ -144,9 +144,9 @@ packages: resolution: {integrity: sha512-qrSfCYxYQB5owCmGLbl8XRpX1ytXlpueOb0N0UmQwA073KZxejgQTzAmJezxvpwQD9uGtK2shHdi55QT+MbjIw==} engines: {node: '>=6.9.0'} dependencies: - '@babel/types': 7.23.6 - '@jridgewell/gen-mapping': 0.3.3 - '@jridgewell/trace-mapping': 0.3.21 + '@babel/types': 7.24.0 + '@jridgewell/gen-mapping': 0.3.5 + '@jridgewell/trace-mapping': 0.3.25 jsesc: 2.5.2 dev: true @@ -156,7 +156,7 @@ packages: dependencies: '@babel/compat-data': 7.23.5 '@babel/helper-validator-option': 7.23.5 - browserslist: 4.22.2 + browserslist: 4.23.0 lru-cache: 5.1.1 semver: 6.3.1 dev: true @@ -170,31 +170,31 @@ packages: resolution: {integrity: sha512-OErEqsrxjZTJciZ4Oo+eoZqeW9UIiOcuYKRJA4ZAgV9myA+pOXhhmpfNCKjEH/auVfEYVFJ6y1Tc4r0eIApqiw==} engines: {node: '>=6.9.0'} dependencies: - '@babel/template': 7.22.15 - '@babel/types': 7.23.6 + '@babel/template': 7.24.0 + '@babel/types': 7.24.0 dev: true /@babel/helper-hoist-variables@7.22.5: resolution: {integrity: sha512-wGjk9QZVzvknA6yKIUURb8zY3grXCcOZt+/7Wcy8O2uctxhplmUPkOdlgoNhmdVee2c92JXbf1xpMtVNbfoxRw==} engines: {node: '>=6.9.0'} dependencies: - '@babel/types': 7.23.6 + '@babel/types': 7.24.0 dev: true /@babel/helper-module-imports@7.22.15: resolution: {integrity: sha512-0pYVBnDKZO2fnSPCrgM/6WMc7eS20Fbok+0r88fp+YtWVLZrp4CkafFGIp+W0VKw4a22sgebPT99y+FDNMdP4w==} engines: {node: '>=6.9.0'} dependencies: - '@babel/types': 7.23.6 + '@babel/types': 7.24.0 dev: true - /@babel/helper-module-transforms@7.23.3(@babel/core@7.23.7): + /@babel/helper-module-transforms@7.23.3(@babel/core@7.24.0): resolution: {integrity: sha512-7bBs4ED9OmswdfDzpz4MpWgSrV7FXlc3zIagvLFjS5H+Mk7Snr21vQ6QwrsoCGMfNC4e4LQPdoULEt4ykz0SRQ==} engines: {node: '>=6.9.0'} peerDependencies: '@babel/core': ^7.0.0 dependencies: - '@babel/core': 7.23.7 + '@babel/core': 7.24.0 '@babel/helper-environment-visitor': 7.22.20 '@babel/helper-module-imports': 7.22.15 '@babel/helper-simple-access': 7.22.5 @@ -202,8 +202,8 @@ packages: '@babel/helper-validator-identifier': 7.22.20 dev: true - /@babel/helper-plugin-utils@7.22.5: - resolution: {integrity: sha512-uLls06UVKgFG9QD4OeFYLEGteMIAa5kpTPcFL28yuCIIzsf6ZyKZMllKVOCZFhiZ5ptnwX4mtKdWCBE/uT4amg==} + /@babel/helper-plugin-utils@7.24.0: + resolution: {integrity: sha512-9cUznXMG0+FxRuJfvL82QlTqIzhVW9sL0KjMPHhAOOvpQGL8QtdxnBKILjBqxlHyliz0yCa1G903ZXI/FuHy2w==} engines: {node: '>=6.9.0'} dev: true @@ -211,14 +211,14 @@ packages: resolution: {integrity: sha512-n0H99E/K+Bika3++WNL17POvo4rKWZ7lZEp1Q+fStVbUi8nxPQEBOlTmCOxW/0JsS56SKKQ+ojAe2pHKJHN35w==} engines: {node: '>=6.9.0'} dependencies: - '@babel/types': 7.23.6 + '@babel/types': 7.24.0 dev: true /@babel/helper-split-export-declaration@7.22.6: resolution: {integrity: sha512-AsUnxuLhRYsisFiaJwvp1QF+I3KjD5FOxut14q/GzovUe6orHLesW2C7d754kRm53h5gqrz6sFl6sxc4BVtE/g==} engines: {node: '>=6.9.0'} dependencies: - '@babel/types': 7.23.6 + '@babel/types': 7.24.0 dev: true /@babel/helper-string-parser@7.23.4: @@ -236,13 +236,13 @@ packages: engines: {node: '>=6.9.0'} dev: true - /@babel/helpers@7.23.8: - resolution: {integrity: sha512-KDqYz4PiOWvDFrdHLPhKtCThtIcKVy6avWD2oG4GEvyQ+XDZwHD4YQd+H2vNMnq2rkdxsDkU82T+Vk8U/WXHRQ==} + /@babel/helpers@7.24.0: + resolution: {integrity: sha512-ulDZdc0Aj5uLc5nETsa7EPx2L7rM0YJM8r7ck7U73AXi7qOV44IHHRAYZHY6iU1rr3C5N4NtTmMRUJP6kwCWeA==} engines: {node: '>=6.9.0'} dependencies: - '@babel/template': 7.22.15 - '@babel/traverse': 7.23.7 - '@babel/types': 7.23.6 + '@babel/template': 7.24.0 + '@babel/traverse': 7.24.0 + '@babel/types': 7.24.0 transitivePeerDependencies: - supports-color dev: true @@ -256,154 +256,154 @@ packages: js-tokens: 4.0.0 dev: true - /@babel/parser@7.23.6: - resolution: {integrity: sha512-Z2uID7YJ7oNvAI20O9X0bblw7Qqs8Q2hFy0R9tAfnfLkp5MW0UH9eUvnDSnFwKZ0AvgS1ucqR4KzvVHgnke1VQ==} + /@babel/parser@7.24.0: + resolution: {integrity: sha512-QuP/FxEAzMSjXygs8v4N9dvdXzEHN4W1oF3PxuWAtPo08UdM17u89RDMgjLn/mlc56iM0HlLmVkO/wgR+rDgHg==} engines: {node: '>=6.0.0'} hasBin: true dependencies: - '@babel/types': 7.23.6 + '@babel/types': 7.24.0 dev: true - /@babel/plugin-syntax-async-generators@7.8.4(@babel/core@7.23.7): + /@babel/plugin-syntax-async-generators@7.8.4(@babel/core@7.24.0): resolution: {integrity: sha512-tycmZxkGfZaxhMRbXlPXuVFpdWlXpir2W4AMhSJgRKzk/eDlIXOhb2LHWoLpDF7TEHylV5zNhykX6KAgHJmTNw==} peerDependencies: '@babel/core': ^7.0.0-0 dependencies: - '@babel/core': 7.23.7 - '@babel/helper-plugin-utils': 7.22.5 + '@babel/core': 7.24.0 + '@babel/helper-plugin-utils': 7.24.0 dev: true - /@babel/plugin-syntax-bigint@7.8.3(@babel/core@7.23.7): + /@babel/plugin-syntax-bigint@7.8.3(@babel/core@7.24.0): resolution: {integrity: sha512-wnTnFlG+YxQm3vDxpGE57Pj0srRU4sHE/mDkt1qv2YJJSeUAec2ma4WLUnUPeKjyrfntVwe/N6dCXpU+zL3Npg==} peerDependencies: '@babel/core': ^7.0.0-0 dependencies: - '@babel/core': 7.23.7 - '@babel/helper-plugin-utils': 7.22.5 + '@babel/core': 7.24.0 + '@babel/helper-plugin-utils': 7.24.0 dev: true - /@babel/plugin-syntax-class-properties@7.12.13(@babel/core@7.23.7): + /@babel/plugin-syntax-class-properties@7.12.13(@babel/core@7.24.0): resolution: {integrity: sha512-fm4idjKla0YahUNgFNLCB0qySdsoPiZP3iQE3rky0mBUtMZ23yDJ9SJdg6dXTSDnulOVqiF3Hgr9nbXvXTQZYA==} peerDependencies: '@babel/core': ^7.0.0-0 dependencies: - '@babel/core': 7.23.7 - '@babel/helper-plugin-utils': 7.22.5 + '@babel/core': 7.24.0 + '@babel/helper-plugin-utils': 7.24.0 dev: true - /@babel/plugin-syntax-import-meta@7.10.4(@babel/core@7.23.7): + /@babel/plugin-syntax-import-meta@7.10.4(@babel/core@7.24.0): resolution: {integrity: sha512-Yqfm+XDx0+Prh3VSeEQCPU81yC+JWZ2pDPFSS4ZdpfZhp4MkFMaDC1UqseovEKwSUpnIL7+vK+Clp7bfh0iD7g==} peerDependencies: '@babel/core': ^7.0.0-0 dependencies: - '@babel/core': 7.23.7 - '@babel/helper-plugin-utils': 7.22.5 + '@babel/core': 7.24.0 + '@babel/helper-plugin-utils': 7.24.0 dev: true - /@babel/plugin-syntax-json-strings@7.8.3(@babel/core@7.23.7): + /@babel/plugin-syntax-json-strings@7.8.3(@babel/core@7.24.0): resolution: {integrity: sha512-lY6kdGpWHvjoe2vk4WrAapEuBR69EMxZl+RoGRhrFGNYVK8mOPAW8VfbT/ZgrFbXlDNiiaxQnAtgVCZ6jv30EA==} peerDependencies: '@babel/core': ^7.0.0-0 dependencies: - '@babel/core': 7.23.7 - '@babel/helper-plugin-utils': 7.22.5 + '@babel/core': 7.24.0 + '@babel/helper-plugin-utils': 7.24.0 dev: true - /@babel/plugin-syntax-jsx@7.23.3(@babel/core@7.23.7): + /@babel/plugin-syntax-jsx@7.23.3(@babel/core@7.24.0): resolution: {integrity: sha512-EB2MELswq55OHUoRZLGg/zC7QWUKfNLpE57m/S2yr1uEneIgsTgrSzXP3NXEsMkVn76OlaVVnzN+ugObuYGwhg==} engines: {node: '>=6.9.0'} peerDependencies: '@babel/core': ^7.0.0-0 dependencies: - '@babel/core': 7.23.7 - '@babel/helper-plugin-utils': 7.22.5 + '@babel/core': 7.24.0 + '@babel/helper-plugin-utils': 7.24.0 dev: true - /@babel/plugin-syntax-logical-assignment-operators@7.10.4(@babel/core@7.23.7): + /@babel/plugin-syntax-logical-assignment-operators@7.10.4(@babel/core@7.24.0): resolution: {integrity: sha512-d8waShlpFDinQ5MtvGU9xDAOzKH47+FFoney2baFIoMr952hKOLp1HR7VszoZvOsV/4+RRszNY7D17ba0te0ig==} peerDependencies: '@babel/core': ^7.0.0-0 dependencies: - '@babel/core': 7.23.7 - '@babel/helper-plugin-utils': 7.22.5 + '@babel/core': 7.24.0 + '@babel/helper-plugin-utils': 7.24.0 dev: true - /@babel/plugin-syntax-nullish-coalescing-operator@7.8.3(@babel/core@7.23.7): + /@babel/plugin-syntax-nullish-coalescing-operator@7.8.3(@babel/core@7.24.0): resolution: {integrity: sha512-aSff4zPII1u2QD7y+F8oDsz19ew4IGEJg9SVW+bqwpwtfFleiQDMdzA/R+UlWDzfnHFCxxleFT0PMIrR36XLNQ==} peerDependencies: '@babel/core': ^7.0.0-0 dependencies: - '@babel/core': 7.23.7 - '@babel/helper-plugin-utils': 7.22.5 + '@babel/core': 7.24.0 + '@babel/helper-plugin-utils': 7.24.0 dev: true - /@babel/plugin-syntax-numeric-separator@7.10.4(@babel/core@7.23.7): + /@babel/plugin-syntax-numeric-separator@7.10.4(@babel/core@7.24.0): resolution: {integrity: sha512-9H6YdfkcK/uOnY/K7/aA2xpzaAgkQn37yzWUMRK7OaPOqOpGS1+n0H5hxT9AUw9EsSjPW8SVyMJwYRtWs3X3ug==} peerDependencies: '@babel/core': ^7.0.0-0 dependencies: - '@babel/core': 7.23.7 - '@babel/helper-plugin-utils': 7.22.5 + '@babel/core': 7.24.0 + '@babel/helper-plugin-utils': 7.24.0 dev: true - /@babel/plugin-syntax-object-rest-spread@7.8.3(@babel/core@7.23.7): + /@babel/plugin-syntax-object-rest-spread@7.8.3(@babel/core@7.24.0): resolution: {integrity: sha512-XoqMijGZb9y3y2XskN+P1wUGiVwWZ5JmoDRwx5+3GmEplNyVM2s2Dg8ILFQm8rWM48orGy5YpI5Bl8U1y7ydlA==} peerDependencies: '@babel/core': ^7.0.0-0 dependencies: - '@babel/core': 7.23.7 - '@babel/helper-plugin-utils': 7.22.5 + '@babel/core': 7.24.0 + '@babel/helper-plugin-utils': 7.24.0 dev: true - /@babel/plugin-syntax-optional-catch-binding@7.8.3(@babel/core@7.23.7): + /@babel/plugin-syntax-optional-catch-binding@7.8.3(@babel/core@7.24.0): resolution: {integrity: sha512-6VPD0Pc1lpTqw0aKoeRTMiB+kWhAoT24PA+ksWSBrFtl5SIRVpZlwN3NNPQjehA2E/91FV3RjLWoVTglWcSV3Q==} peerDependencies: '@babel/core': ^7.0.0-0 dependencies: - '@babel/core': 7.23.7 - '@babel/helper-plugin-utils': 7.22.5 + '@babel/core': 7.24.0 + '@babel/helper-plugin-utils': 7.24.0 dev: true - /@babel/plugin-syntax-optional-chaining@7.8.3(@babel/core@7.23.7): + /@babel/plugin-syntax-optional-chaining@7.8.3(@babel/core@7.24.0): resolution: {integrity: sha512-KoK9ErH1MBlCPxV0VANkXW2/dw4vlbGDrFgz8bmUsBGYkFRcbRwMh6cIJubdPrkxRwuGdtCk0v/wPTKbQgBjkg==} peerDependencies: '@babel/core': ^7.0.0-0 dependencies: - '@babel/core': 7.23.7 - '@babel/helper-plugin-utils': 7.22.5 + '@babel/core': 7.24.0 + '@babel/helper-plugin-utils': 7.24.0 dev: true - /@babel/plugin-syntax-top-level-await@7.14.5(@babel/core@7.23.7): + /@babel/plugin-syntax-top-level-await@7.14.5(@babel/core@7.24.0): resolution: {integrity: sha512-hx++upLv5U1rgYfwe1xBQUhRmU41NEvpUvrp8jkrSCdvGSnM5/qdRMtylJ6PG5OFkBaHkbTAKTnd3/YyESRHFw==} engines: {node: '>=6.9.0'} peerDependencies: '@babel/core': ^7.0.0-0 dependencies: - '@babel/core': 7.23.7 - '@babel/helper-plugin-utils': 7.22.5 + '@babel/core': 7.24.0 + '@babel/helper-plugin-utils': 7.24.0 dev: true - /@babel/plugin-syntax-typescript@7.23.3(@babel/core@7.23.7): + /@babel/plugin-syntax-typescript@7.23.3(@babel/core@7.24.0): resolution: {integrity: sha512-9EiNjVJOMwCO+43TqoTrgQ8jMwcAd0sWyXi9RPfIsLTj4R2MADDDQXELhffaUx/uJv2AYcxBgPwH6j4TIA4ytQ==} engines: {node: '>=6.9.0'} peerDependencies: '@babel/core': ^7.0.0-0 dependencies: - '@babel/core': 7.23.7 - '@babel/helper-plugin-utils': 7.22.5 + '@babel/core': 7.24.0 + '@babel/helper-plugin-utils': 7.24.0 dev: true - /@babel/template@7.22.15: - resolution: {integrity: sha512-QPErUVm4uyJa60rkI73qneDacvdvzxshT3kksGqlGWYdOTIUOwJ7RDUL8sGqslY1uXWSL6xMFKEXDS3ox2uF0w==} + /@babel/template@7.24.0: + resolution: {integrity: sha512-Bkf2q8lMB0AFpX0NFEqSbx1OkTHf0f+0j82mkw+ZpzBnkk7e9Ql0891vlfgi+kHwOk8tQjiQHpqh4LaSa0fKEA==} engines: {node: '>=6.9.0'} dependencies: '@babel/code-frame': 7.23.5 - '@babel/parser': 7.23.6 - '@babel/types': 7.23.6 + '@babel/parser': 7.24.0 + '@babel/types': 7.24.0 dev: true - /@babel/traverse@7.23.7: - resolution: {integrity: sha512-tY3mM8rH9jM0YHFGyfC0/xf+SB5eKUu7HPj7/k3fpi9dAlsMc5YbQvDi0Sh2QTPXqMhyaAtzAr807TIyfQrmyg==} + /@babel/traverse@7.24.0: + resolution: {integrity: sha512-HfuJlI8qq3dEDmNU5ChzzpZRWq+oxCZQyMzIMEqLho+AQnhMnKQUzH6ydo3RBl/YjPCuk68Y6s0Gx0AeyULiWw==} engines: {node: '>=6.9.0'} dependencies: '@babel/code-frame': 7.23.5 @@ -412,16 +412,16 @@ packages: '@babel/helper-function-name': 7.23.0 '@babel/helper-hoist-variables': 7.22.5 '@babel/helper-split-export-declaration': 7.22.6 - '@babel/parser': 7.23.6 - '@babel/types': 7.23.6 + '@babel/parser': 7.24.0 + '@babel/types': 7.24.0 debug: 4.3.4(supports-color@8.1.1) globals: 11.12.0 transitivePeerDependencies: - supports-color dev: true - /@babel/types@7.23.6: - resolution: {integrity: sha512-+uarb83brBzPKN38NX1MkB6vb6+mwvR6amUulqAE7ccQw1pEl+bCia9TbdG1lsnFP7lZySvUn37CHyXQdfTwzg==} + /@babel/types@7.24.0: + resolution: {integrity: sha512-+j7a5c253RfKh8iABBhywc8NSfP5LURe7Uh4qpsh6jc+aLJguvmIUBdjSdEMQv2bENrCR5MfRdjGo7vzS/ob7w==} engines: {node: '>=6.9.0'} dependencies: '@babel/helper-string-parser': 7.23.4 @@ -433,20 +433,20 @@ packages: resolution: {integrity: sha512-0hYQ8SB4Db5zvZB4axdMHGwEaQjkZzFjQiN9LVYvIFB2nSUHW9tYpxWriPrWDASIxiaXax83REcLxuSdnGPZtw==} dev: true - /@codemirror/state@6.4.0: - resolution: {integrity: sha512-hm8XshYj5Fo30Bb922QX9hXB/bxOAVH+qaqHBzw5TKa72vOeslyGwd4X8M0c1dJ9JqxlaMceOQ8RsL9tC7gU0A==} + /@codemirror/state@6.4.1: + resolution: {integrity: sha512-QkEyUiLhsJoZkbumGZlswmAhA7CBU02Wrz7zvH4SrcifbsqwlXShVXg65f3v/ts57W3dqyamEriMhij1Z3Zz4A==} dev: true - /@codemirror/view@6.23.0: - resolution: {integrity: sha512-/51px9N4uW8NpuWkyUX+iam5+PM6io2fm+QmRnzwqBy5v/pwGg9T0kILFtYeum8hjuvENtgsGNKluOfqIICmeQ==} + /@codemirror/view@6.24.1: + resolution: {integrity: sha512-sBfP4rniPBRQzNakwuQEqjEuiJDWJyF2kqLLqij4WXRoVwPPJfjx966Eq3F7+OPQxDtMt/Q9MWLoZLWjeveBlg==} dependencies: - '@codemirror/state': 6.4.0 - style-mod: 4.1.0 + '@codemirror/state': 6.4.1 + style-mod: 4.1.2 w3c-keyname: 2.2.8 dev: true - /@esbuild/aix-ppc64@0.19.11: - resolution: {integrity: sha512-FnzU0LyE3ySQk7UntJO4+qIiQgI7KoODnZg5xzXIrFJlKd2P2gwHsHY4927xj9y5PJmJSzULiUCWmv7iWnNa7g==} + /@esbuild/aix-ppc64@0.19.12: + resolution: {integrity: sha512-bmoCYyWdEL3wDQIVbcyzRyeKLgk2WtWLTWz1ZIAZF/EGbNOwSA6ew3PftJ1PqMiOOGu0OyFMzG53L0zqIpPeNA==} engines: {node: '>=12'} cpu: [ppc64] os: [aix] @@ -454,8 +454,8 @@ packages: dev: true optional: true - /@esbuild/android-arm64@0.19.11: - resolution: {integrity: sha512-aiu7K/5JnLj//KOnOfEZ0D90obUkRzDMyqd/wNAUQ34m4YUPVhRZpnqKV9uqDGxT7cToSDnIHsGooyIczu9T+Q==} + /@esbuild/android-arm64@0.19.12: + resolution: {integrity: sha512-P0UVNGIienjZv3f5zq0DP3Nt2IE/3plFzuaS96vihvD0Hd6H/q4WXUGpCxD/E8YrSXfNyRPbpTq+T8ZQioSuPA==} engines: {node: '>=12'} cpu: [arm64] os: [android] @@ -463,8 +463,8 @@ packages: dev: true optional: true - /@esbuild/android-arm@0.19.11: - resolution: {integrity: sha512-5OVapq0ClabvKvQ58Bws8+wkLCV+Rxg7tUVbo9xu034Nm536QTII4YzhaFriQ7rMrorfnFKUsArD2lqKbFY4vw==} + /@esbuild/android-arm@0.19.12: + resolution: {integrity: sha512-qg/Lj1mu3CdQlDEEiWrlC4eaPZ1KztwGJ9B6J+/6G+/4ewxJg7gqj8eVYWvao1bXrqGiW2rsBZFSX3q2lcW05w==} engines: {node: '>=12'} cpu: [arm] os: [android] @@ -472,8 +472,8 @@ packages: dev: true optional: true - /@esbuild/android-x64@0.19.11: - resolution: {integrity: sha512-eccxjlfGw43WYoY9QgB82SgGgDbibcqyDTlk3l3C0jOVHKxrjdc9CTwDUQd0vkvYg5um0OH+GpxYvp39r+IPOg==} + /@esbuild/android-x64@0.19.12: + resolution: {integrity: sha512-3k7ZoUW6Q6YqhdhIaq/WZ7HwBpnFBlW905Fa4s4qWJyiNOgT1dOqDiVAQFwBH7gBRZr17gLrlFCRzF6jFh7Kew==} engines: {node: '>=12'} cpu: [x64] os: [android] @@ -481,8 +481,8 @@ packages: dev: true optional: true - /@esbuild/darwin-arm64@0.19.11: - resolution: {integrity: sha512-ETp87DRWuSt9KdDVkqSoKoLFHYTrkyz2+65fj9nfXsaV3bMhTCjtQfw3y+um88vGRKRiF7erPrh/ZuIdLUIVxQ==} + /@esbuild/darwin-arm64@0.19.12: + resolution: {integrity: sha512-B6IeSgZgtEzGC42jsI+YYu9Z3HKRxp8ZT3cqhvliEHovq8HSX2YX8lNocDn79gCKJXOSaEot9MVYky7AKjCs8g==} engines: {node: '>=12'} cpu: [arm64] os: [darwin] @@ -490,8 +490,8 @@ packages: dev: true optional: true - /@esbuild/darwin-x64@0.19.11: - resolution: {integrity: sha512-fkFUiS6IUK9WYUO/+22omwetaSNl5/A8giXvQlcinLIjVkxwTLSktbF5f/kJMftM2MJp9+fXqZ5ezS7+SALp4g==} + /@esbuild/darwin-x64@0.19.12: + resolution: {integrity: sha512-hKoVkKzFiToTgn+41qGhsUJXFlIjxI/jSYeZf3ugemDYZldIXIxhvwN6erJGlX4t5h417iFuheZ7l+YVn05N3A==} engines: {node: '>=12'} cpu: [x64] os: [darwin] @@ -499,8 +499,8 @@ packages: dev: true optional: true - /@esbuild/freebsd-arm64@0.19.11: - resolution: {integrity: sha512-lhoSp5K6bxKRNdXUtHoNc5HhbXVCS8V0iZmDvyWvYq9S5WSfTIHU2UGjcGt7UeS6iEYp9eeymIl5mJBn0yiuxA==} + /@esbuild/freebsd-arm64@0.19.12: + resolution: {integrity: sha512-4aRvFIXmwAcDBw9AueDQ2YnGmz5L6obe5kmPT8Vd+/+x/JMVKCgdcRwH6APrbpNXsPz+K653Qg8HB/oXvXVukA==} engines: {node: '>=12'} cpu: [arm64] os: [freebsd] @@ -508,8 +508,8 @@ packages: dev: true optional: true - /@esbuild/freebsd-x64@0.19.11: - resolution: {integrity: sha512-JkUqn44AffGXitVI6/AbQdoYAq0TEullFdqcMY/PCUZ36xJ9ZJRtQabzMA+Vi7r78+25ZIBosLTOKnUXBSi1Kw==} + /@esbuild/freebsd-x64@0.19.12: + resolution: {integrity: sha512-EYoXZ4d8xtBoVN7CEwWY2IN4ho76xjYXqSXMNccFSx2lgqOG/1TBPW0yPx1bJZk94qu3tX0fycJeeQsKovA8gg==} engines: {node: '>=12'} cpu: [x64] os: [freebsd] @@ -517,8 +517,8 @@ packages: dev: true optional: true - /@esbuild/linux-arm64@0.19.11: - resolution: {integrity: sha512-LneLg3ypEeveBSMuoa0kwMpCGmpu8XQUh+mL8XXwoYZ6Be2qBnVtcDI5azSvh7vioMDhoJFZzp9GWp9IWpYoUg==} + /@esbuild/linux-arm64@0.19.12: + resolution: {integrity: sha512-EoTjyYyLuVPfdPLsGVVVC8a0p1BFFvtpQDB/YLEhaXyf/5bczaGeN15QkR+O4S5LeJ92Tqotve7i1jn35qwvdA==} engines: {node: '>=12'} cpu: [arm64] os: [linux] @@ -526,8 +526,8 @@ packages: dev: true optional: true - /@esbuild/linux-arm@0.19.11: - resolution: {integrity: sha512-3CRkr9+vCV2XJbjwgzjPtO8T0SZUmRZla+UL1jw+XqHZPkPgZiyWvbDvl9rqAN8Zl7qJF0O/9ycMtjU67HN9/Q==} + /@esbuild/linux-arm@0.19.12: + resolution: {integrity: sha512-J5jPms//KhSNv+LO1S1TX1UWp1ucM6N6XuL6ITdKWElCu8wXP72l9MM0zDTzzeikVyqFE6U8YAV9/tFyj0ti+w==} engines: {node: '>=12'} cpu: [arm] os: [linux] @@ -535,8 +535,8 @@ packages: dev: true optional: true - /@esbuild/linux-ia32@0.19.11: - resolution: {integrity: sha512-caHy++CsD8Bgq2V5CodbJjFPEiDPq8JJmBdeyZ8GWVQMjRD0sU548nNdwPNvKjVpamYYVL40AORekgfIubwHoA==} + /@esbuild/linux-ia32@0.19.12: + resolution: {integrity: sha512-Thsa42rrP1+UIGaWz47uydHSBOgTUnwBwNq59khgIwktK6x60Hivfbux9iNR0eHCHzOLjLMLfUMLCypBkZXMHA==} engines: {node: '>=12'} cpu: [ia32] os: [linux] @@ -544,8 +544,8 @@ packages: dev: true optional: true - /@esbuild/linux-loong64@0.19.11: - resolution: {integrity: sha512-ppZSSLVpPrwHccvC6nQVZaSHlFsvCQyjnvirnVjbKSHuE5N24Yl8F3UwYUUR1UEPaFObGD2tSvVKbvR+uT1Nrg==} + /@esbuild/linux-loong64@0.19.12: + resolution: {integrity: sha512-LiXdXA0s3IqRRjm6rV6XaWATScKAXjI4R4LoDlvO7+yQqFdlr1Bax62sRwkVvRIrwXxvtYEHHI4dm50jAXkuAA==} engines: {node: '>=12'} cpu: [loong64] os: [linux] @@ -553,8 +553,8 @@ packages: dev: true optional: true - /@esbuild/linux-mips64el@0.19.11: - resolution: {integrity: sha512-B5x9j0OgjG+v1dF2DkH34lr+7Gmv0kzX6/V0afF41FkPMMqaQ77pH7CrhWeR22aEeHKaeZVtZ6yFwlxOKPVFyg==} + /@esbuild/linux-mips64el@0.19.12: + resolution: {integrity: sha512-fEnAuj5VGTanfJ07ff0gOA6IPsvrVHLVb6Lyd1g2/ed67oU1eFzL0r9WL7ZzscD+/N6i3dWumGE1Un4f7Amf+w==} engines: {node: '>=12'} cpu: [mips64el] os: [linux] @@ -562,8 +562,8 @@ packages: dev: true optional: true - /@esbuild/linux-ppc64@0.19.11: - resolution: {integrity: sha512-MHrZYLeCG8vXblMetWyttkdVRjQlQUb/oMgBNurVEnhj4YWOr4G5lmBfZjHYQHHN0g6yDmCAQRR8MUHldvvRDA==} + /@esbuild/linux-ppc64@0.19.12: + resolution: {integrity: sha512-nYJA2/QPimDQOh1rKWedNOe3Gfc8PabU7HT3iXWtNUbRzXS9+vgB0Fjaqr//XNbd82mCxHzik2qotuI89cfixg==} engines: {node: '>=12'} cpu: [ppc64] os: [linux] @@ -571,8 +571,8 @@ packages: dev: true optional: true - /@esbuild/linux-riscv64@0.19.11: - resolution: {integrity: sha512-f3DY++t94uVg141dozDu4CCUkYW+09rWtaWfnb3bqe4w5NqmZd6nPVBm+qbz7WaHZCoqXqHz5p6CM6qv3qnSSQ==} + /@esbuild/linux-riscv64@0.19.12: + resolution: {integrity: sha512-2MueBrlPQCw5dVJJpQdUYgeqIzDQgw3QtiAHUC4RBz9FXPrskyyU3VI1hw7C0BSKB9OduwSJ79FTCqtGMWqJHg==} engines: {node: '>=12'} cpu: [riscv64] os: [linux] @@ -580,8 +580,8 @@ packages: dev: true optional: true - /@esbuild/linux-s390x@0.19.11: - resolution: {integrity: sha512-A5xdUoyWJHMMlcSMcPGVLzYzpcY8QP1RtYzX5/bS4dvjBGVxdhuiYyFwp7z74ocV7WDc0n1harxmpq2ePOjI0Q==} + /@esbuild/linux-s390x@0.19.12: + resolution: {integrity: sha512-+Pil1Nv3Umes4m3AZKqA2anfhJiVmNCYkPchwFJNEJN5QxmTs1uzyy4TvmDrCRNT2ApwSari7ZIgrPeUx4UZDg==} engines: {node: '>=12'} cpu: [s390x] os: [linux] @@ -589,8 +589,8 @@ packages: dev: true optional: true - /@esbuild/linux-x64@0.19.11: - resolution: {integrity: sha512-grbyMlVCvJSfxFQUndw5mCtWs5LO1gUlwP4CDi4iJBbVpZcqLVT29FxgGuBJGSzyOxotFG4LoO5X+M1350zmPA==} + /@esbuild/linux-x64@0.19.12: + resolution: {integrity: sha512-B71g1QpxfwBvNrfyJdVDexenDIt1CiDN1TIXLbhOw0KhJzE78KIFGX6OJ9MrtC0oOqMWf+0xop4qEU8JrJTwCg==} engines: {node: '>=12'} cpu: [x64] os: [linux] @@ -598,8 +598,8 @@ packages: dev: true optional: true - /@esbuild/netbsd-x64@0.19.11: - resolution: {integrity: sha512-13jvrQZJc3P230OhU8xgwUnDeuC/9egsjTkXN49b3GcS5BKvJqZn86aGM8W9pd14Kd+u7HuFBMVtrNGhh6fHEQ==} + /@esbuild/netbsd-x64@0.19.12: + resolution: {integrity: sha512-3ltjQ7n1owJgFbuC61Oj++XhtzmymoCihNFgT84UAmJnxJfm4sYCiSLTXZtE00VWYpPMYc+ZQmB6xbSdVh0JWA==} engines: {node: '>=12'} cpu: [x64] os: [netbsd] @@ -607,8 +607,8 @@ packages: dev: true optional: true - /@esbuild/openbsd-x64@0.19.11: - resolution: {integrity: sha512-ysyOGZuTp6SNKPE11INDUeFVVQFrhcNDVUgSQVDzqsqX38DjhPEPATpid04LCoUr2WXhQTEZ8ct/EgJCUDpyNw==} + /@esbuild/openbsd-x64@0.19.12: + resolution: {integrity: sha512-RbrfTB9SWsr0kWmb9srfF+L933uMDdu9BIzdA7os2t0TXhCRjrQyCeOt6wVxr79CKD4c+p+YhCj31HBkYcXebw==} engines: {node: '>=12'} cpu: [x64] os: [openbsd] @@ -616,8 +616,8 @@ packages: dev: true optional: true - /@esbuild/sunos-x64@0.19.11: - resolution: {integrity: sha512-Hf+Sad9nVwvtxy4DXCZQqLpgmRTQqyFyhT3bZ4F2XlJCjxGmRFF0Shwn9rzhOYRB61w9VMXUkxlBy56dk9JJiQ==} + /@esbuild/sunos-x64@0.19.12: + resolution: {integrity: sha512-HKjJwRrW8uWtCQnQOz9qcU3mUZhTUQvi56Q8DPTLLB+DawoiQdjsYq+j+D3s9I8VFtDr+F9CjgXKKC4ss89IeA==} engines: {node: '>=12'} cpu: [x64] os: [sunos] @@ -625,8 +625,8 @@ packages: dev: true optional: true - /@esbuild/win32-arm64@0.19.11: - resolution: {integrity: sha512-0P58Sbi0LctOMOQbpEOvOL44Ne0sqbS0XWHMvvrg6NE5jQ1xguCSSw9jQeUk2lfrXYsKDdOe6K+oZiwKPilYPQ==} + /@esbuild/win32-arm64@0.19.12: + resolution: {integrity: sha512-URgtR1dJnmGvX864pn1B2YUYNzjmXkuJOIqG2HdU62MVS4EHpU2946OZoTMnRUHklGtJdJZ33QfzdjGACXhn1A==} engines: {node: '>=12'} cpu: [arm64] os: [win32] @@ -634,8 +634,8 @@ packages: dev: true optional: true - /@esbuild/win32-ia32@0.19.11: - resolution: {integrity: sha512-6YOrWS+sDJDmshdBIQU+Uoyh7pQKrdykdefC1avn76ss5c+RN6gut3LZA4E2cH5xUEp5/cA0+YxRaVtRAb0xBg==} + /@esbuild/win32-ia32@0.19.12: + resolution: {integrity: sha512-+ZOE6pUkMOJfmxmBZElNOx72NKpIa/HFOMGzu8fqzQJ5kgf6aTGrcJaFsNiVMH4JKpMipyK+7k0n2UXN7a8YKQ==} engines: {node: '>=12'} cpu: [ia32] os: [win32] @@ -643,8 +643,8 @@ packages: dev: true optional: true - /@esbuild/win32-x64@0.19.11: - resolution: {integrity: sha512-vfkhltrjCAb603XaFhqhAF4LGDi2M4OrCRrFusyQ+iTLQ/o60QQXxc9cZC/FFpihBI9N1Grn6SMKVJ4KP7Fuiw==} + /@esbuild/win32-x64@0.19.12: + resolution: {integrity: sha512-T1QyPSDCyMXaO3pzBkF96E8xMkiRYbUEZADd29SyPGabqxMViNoii+NcK7eWJAEoU6RZyEm5lVSIjTmcdoB9HA==} engines: {node: '>=12'} cpu: [x64] os: [win32] @@ -652,13 +652,13 @@ packages: dev: true optional: true - /@eslint-community/eslint-utils@4.4.0(eslint@8.56.0): + /@eslint-community/eslint-utils@4.4.0(eslint@8.57.0): resolution: {integrity: sha512-1/sA4dwrzBAyeUoQ6oxahHKmrZvsnLCg4RfxW3ZFGGmQkSNQPFNLV9CUEFQP1x9EYXHTo5p6xdhZM1Ne9p/AfA==} engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} peerDependencies: eslint: ^6.0.0 || ^7.0.0 || >=8.0.0 dependencies: - eslint: 8.56.0 + eslint: 8.57.0 eslint-visitor-keys: 3.4.3 dev: true @@ -675,7 +675,7 @@ packages: debug: 4.3.4(supports-color@8.1.1) espree: 9.6.1 globals: 13.24.0 - ignore: 5.3.0 + ignore: 5.3.1 import-fresh: 3.3.0 js-yaml: 4.1.0 minimatch: 3.1.2 @@ -684,8 +684,8 @@ packages: - supports-color dev: true - /@eslint/js@8.56.0: - resolution: {integrity: sha512-gMsVel9D7f2HLkBma9VbtzZRehRogVRfbr++f06nL2vnCGCNlzOD+/MUov/F4p8myyAHspEhVobgjpX64q5m6A==} + /@eslint/js@8.57.0: + resolution: {integrity: sha512-Ys+3g2TaW7gADOJzPt83SJtCDhMjndcDMFVQ/Tj9iA1BfJzFKD9mAUXT3OenpuPHbI6P/myECxRJrofUsDx/5g==} engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} dev: true @@ -742,7 +742,7 @@ packages: engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} dependencies: '@jest/types': 29.6.3 - '@types/node': 20.11.2 + '@types/node': 20.11.24 chalk: 4.1.2 jest-message-util: 29.7.0 jest-util: 29.7.0 @@ -763,14 +763,14 @@ packages: '@jest/test-result': 29.7.0 '@jest/transform': 29.7.0 '@jest/types': 29.6.3 - '@types/node': 20.11.2 + '@types/node': 20.11.24 ansi-escapes: 4.3.2 chalk: 4.1.2 ci-info: 3.9.0 exit: 0.1.2 graceful-fs: 4.2.11 jest-changed-files: 29.7.0 - jest-config: 29.7.0(@types/node@20.11.2) + jest-config: 29.7.0(@types/node@20.11.24) jest-haste-map: 29.7.0 jest-message-util: 29.7.0 jest-regex-util: 29.6.3 @@ -798,7 +798,7 @@ packages: dependencies: '@jest/fake-timers': 29.7.0 '@jest/types': 29.6.3 - '@types/node': 20.11.2 + '@types/node': 20.11.24 jest-mock: 29.7.0 dev: true @@ -825,7 +825,7 @@ packages: dependencies: '@jest/types': 29.6.3 '@sinonjs/fake-timers': 10.3.0 - '@types/node': 20.11.2 + '@types/node': 20.11.24 jest-message-util: 29.7.0 jest-mock: 29.7.0 jest-util: 29.7.0 @@ -857,18 +857,18 @@ packages: '@jest/test-result': 29.7.0 '@jest/transform': 29.7.0 '@jest/types': 29.6.3 - '@jridgewell/trace-mapping': 0.3.21 - '@types/node': 20.11.2 + '@jridgewell/trace-mapping': 0.3.25 + '@types/node': 20.11.24 chalk: 4.1.2 collect-v8-coverage: 1.0.2 exit: 0.1.2 glob: 7.2.3 graceful-fs: 4.2.11 istanbul-lib-coverage: 3.2.2 - istanbul-lib-instrument: 6.0.1 + istanbul-lib-instrument: 6.0.2 istanbul-lib-report: 3.0.1 istanbul-lib-source-maps: 4.0.1 - istanbul-reports: 3.1.6 + istanbul-reports: 3.1.7 jest-message-util: 29.7.0 jest-util: 29.7.0 jest-worker: 29.7.0 @@ -891,7 +891,7 @@ packages: resolution: {integrity: sha512-MHjT95QuipcPrpLM+8JMSzFx6eHp5Bm+4XeFDJlwsvVBjmKNiIAvasGK2fxz2WbGRlnvqehFbh07MMa7n3YJnw==} engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} dependencies: - '@jridgewell/trace-mapping': 0.3.21 + '@jridgewell/trace-mapping': 0.3.25 callsites: 3.1.0 graceful-fs: 4.2.11 dev: true @@ -920,9 +920,9 @@ packages: resolution: {integrity: sha512-ok/BTPFzFKVMwO5eOHRrvnBVHdRy9IrsrW1GpMaQ9MCnilNLXQKmAX8s1YXDFaai9xJpac2ySzV0YeRRECr2Vw==} engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} dependencies: - '@babel/core': 7.23.7 + '@babel/core': 7.24.0 '@jest/types': 29.6.3 - '@jridgewell/trace-mapping': 0.3.21 + '@jridgewell/trace-mapping': 0.3.25 babel-plugin-istanbul: 6.1.1 chalk: 4.1.2 convert-source-map: 2.0.0 @@ -946,27 +946,27 @@ packages: '@jest/schemas': 29.6.3 '@types/istanbul-lib-coverage': 2.0.6 '@types/istanbul-reports': 3.0.4 - '@types/node': 20.11.2 + '@types/node': 20.11.24 '@types/yargs': 17.0.32 chalk: 4.1.2 dev: true - /@jridgewell/gen-mapping@0.3.3: - resolution: {integrity: sha512-HLhSWOLRi875zjjMG/r+Nv0oCW8umGb0BgEhyX3dDX3egwZtB8PqLnjz3yedt8R5StBrzcg4aBpnh8UA9D1BoQ==} + /@jridgewell/gen-mapping@0.3.5: + resolution: {integrity: sha512-IzL8ZoEDIBRWEzlCcRhOaCupYyN5gdIK+Q6fbFdPDg6HqX6jpkItn7DFIpW9LQzXG6Df9sA7+OKnq0qlz/GaQg==} engines: {node: '>=6.0.0'} dependencies: - '@jridgewell/set-array': 1.1.2 + '@jridgewell/set-array': 1.2.1 '@jridgewell/sourcemap-codec': 1.4.15 - '@jridgewell/trace-mapping': 0.3.21 + '@jridgewell/trace-mapping': 0.3.25 dev: true - /@jridgewell/resolve-uri@3.1.1: - resolution: {integrity: sha512-dSYZh7HhCDtCKm4QakX0xFpsRDqjjtZf/kjI/v3T3Nwt5r8/qz/M19F9ySyOqU94SXBmeG9ttTul+YnR4LOxFA==} + /@jridgewell/resolve-uri@3.1.2: + resolution: {integrity: sha512-bRISgCIjP20/tbWSPWMEi54QVPRZExkuD9lJL+UIxUKtwVJA8wW1Trb1jMs1RFXo1CBTNZ/5hpC9QvmKWdopKw==} engines: {node: '>=6.0.0'} dev: true - /@jridgewell/set-array@1.1.2: - resolution: {integrity: sha512-xnkseuNADM0gt2bs+BvhO0p78Mk762YnZdsuzFV018NoG1Sj1SCQvpSqa7XUaTam5vAGasABV9qXASMKnFMwMw==} + /@jridgewell/set-array@1.2.1: + resolution: {integrity: sha512-R8gLRTZeyp03ymzP/6Lil/28tGeGEzhx1q2k703KGWRAI1VdvPIXdG70VJc2pAMw3NA6JKL5hhFu1sJX0Mnn/A==} engines: {node: '>=6.0.0'} dev: true @@ -974,10 +974,10 @@ packages: resolution: {integrity: sha512-eF2rxCRulEKXHTRiDrDy6erMYWqNw4LPdQ8UQA4huuxaQsVeRPFl2oM8oDGxMFhJUWZf9McpLtJasDDZb/Bpeg==} dev: true - /@jridgewell/trace-mapping@0.3.21: - resolution: {integrity: sha512-SRfKmRe1KvYnxjEMtxEr+J4HIeMX5YBg/qhRHpxEIGjhX1rshcHlnFUE9K0GazhVKWM7B+nARSkV8LuvJdJ5/g==} + /@jridgewell/trace-mapping@0.3.25: + resolution: {integrity: sha512-vNk6aEwybGtawWmy/PzwnGDOjCkLWSD2wqvjGGAgOAwCGWySYXfYoxt00IJkTF+8Lb57DwOb3Aa0o9CApepiYQ==} dependencies: - '@jridgewell/resolve-uri': 3.1.1 + '@jridgewell/resolve-uri': 3.1.2 '@jridgewell/sourcemap-codec': 1.4.15 dev: true @@ -985,11 +985,11 @@ packages: resolution: {integrity: sha512-fuscdXJ9G1qb7W8VdHi+IwRqij3lBkosAm4ydQtEmbY58OzHXqQhvlxqEkoz0yssNVn38bcpRWgA9PP+OGoisw==} dev: false - /@ljharb/through@2.3.11: - resolution: {integrity: sha512-ccfcIDlogiXNq5KcbAwbaO7lMh3Tm1i3khMPYpxlK8hH/W53zN81KM9coerRLOnTGu3nfXIniAmQbRI9OxbC0w==} + /@ljharb/through@2.3.12: + resolution: {integrity: sha512-ajo/heTlG3QgC8EGP6APIejksVAYt4ayz4tqoP3MolFELzcH1x1fzwEYRJTPO0IELutZ5HQ0c26/GqAYy79u3g==} engines: {node: '>= 0.4'} dependencies: - call-bind: 1.0.5 + call-bind: 1.0.7 dev: true /@nodelib/fs.scandir@2.1.5: @@ -1010,7 +1010,7 @@ packages: engines: {node: '>= 8'} dependencies: '@nodelib/fs.scandir': 2.1.5 - fastq: 1.16.0 + fastq: 1.17.1 dev: true /@pkgjs/parseargs@0.11.0: @@ -1067,8 +1067,8 @@ packages: engines: {node: '>=14.16'} dev: true - /@sinonjs/commons@3.0.0: - resolution: {integrity: sha512-jXBtWAF4vmdNmZgD5FoKsVLv3rPgDnLgPbU84LIJ3otV44vJlDRokVng5v8NFJdCf/da9legHcKaRuZs4L7faA==} + /@sinonjs/commons@3.0.1: + resolution: {integrity: sha512-K3mCHKQ9sVh8o1C9cxkwxaOmXoAMlDxC1mYyHrjqOWEcBjYr76t96zL2zlj5dUGZ3HSw240X1qgH3Mjf1yJWpQ==} dependencies: type-detect: 4.0.8 dev: true @@ -1076,7 +1076,7 @@ packages: /@sinonjs/fake-timers@10.3.0: resolution: {integrity: sha512-V4BG07kuYSUkTCSBHG8G8TNhM+F19jXFWnQtzj+we8DrkpSBCee9Z3Ms8yiGer/dlmhe35/Xdgyo3/0rQKg7YA==} dependencies: - '@sinonjs/commons': 3.0.0 + '@sinonjs/commons': 3.0.1 dev: true /@szmarczak/http-timer@5.0.1: @@ -1098,8 +1098,8 @@ packages: /@types/babel__core@7.20.5: resolution: {integrity: sha512-qoQprZvz5wQFJwMDqeseRXWv3rqMvhgpbXFfVyWhbx9X47POIA6i/+dXefEmZKoAgOaTdaIgNSMqMIU61yRyzA==} dependencies: - '@babel/parser': 7.23.6 - '@babel/types': 7.23.6 + '@babel/parser': 7.24.0 + '@babel/types': 7.24.0 '@types/babel__generator': 7.6.8 '@types/babel__template': 7.4.4 '@types/babel__traverse': 7.20.5 @@ -1108,20 +1108,20 @@ packages: /@types/babel__generator@7.6.8: resolution: {integrity: sha512-ASsj+tpEDsEiFr1arWrlN6V3mdfjRMZt6LtK/Vp/kreFLnr5QH5+DhvD5nINYZXzwJvXeGq+05iUXcAzVrqWtw==} dependencies: - '@babel/types': 7.23.6 + '@babel/types': 7.24.0 dev: true /@types/babel__template@7.4.4: resolution: {integrity: sha512-h/NUaSyG5EyxBIp8YRxo4RMe2/qQgvyowRwVMzhYhBCONbW8PUsg4lkFMrhgZhUe5z3L3MiLDuvyJ/CaPa2A8A==} dependencies: - '@babel/parser': 7.23.6 - '@babel/types': 7.23.6 + '@babel/parser': 7.24.0 + '@babel/types': 7.24.0 dev: true /@types/babel__traverse@7.20.5: resolution: {integrity: sha512-WXCyOcRtH37HAUkpXhUduaxdm82b4GSlyTqajXviN4EfiuPgNYR109xMCKvpl6zPIpua0DGlMEDCq+g8EdoheQ==} dependencies: - '@babel/types': 7.23.6 + '@babel/types': 7.24.0 dev: true /@types/codemirror@5.60.8: @@ -1137,7 +1137,7 @@ packages: /@types/graceful-fs@4.1.9: resolution: {integrity: sha512-olP3sd1qOEe5dXTSaFvQG+02VdRXcdytWLAZsAq1PecU8uqQAhkrnbli7DagjtXKW/Bl7YJbUsa8MPcuc8LHEQ==} dependencies: - '@types/node': 20.11.2 + '@types/node': 20.11.24 dev: true /@types/http-cache-semantics@4.0.4: @@ -1160,8 +1160,8 @@ packages: '@types/istanbul-lib-report': 3.0.3 dev: true - /@types/jest@29.5.11: - resolution: {integrity: sha512-S2mHmYIVe13vrm6q4kN6fLYYAka15ALQki/vgDC3mIukEOx8WJlv0kQPM+d4w8Gp6u0uSdKND04IlTXBv0rwnQ==} + /@types/jest@29.5.12: + resolution: {integrity: sha512-eDC8bTvT/QhYdxJAulQikueigY5AsdBRH2yDKW3yveW7svY3+DzN84/2NUgkw10RTiJbWqZrTtoGVdYlvFJdLw==} dependencies: expect: 29.7.0 pretty-format: 29.7.0 @@ -1170,7 +1170,7 @@ packages: /@types/jsdom@20.0.1: resolution: {integrity: sha512-d0r18sZPmMQr1eG35u12FZfhIXNrnsPU/g5wvRKCUf/tOGilKKwYMYGqh33BNR6ba+2gkHw1EUiHoN3mn7E5IQ==} dependencies: - '@types/node': 20.11.2 + '@types/node': 20.11.24 '@types/tough-cookie': 4.0.5 parse5: 7.1.2 dev: true @@ -1183,8 +1183,8 @@ packages: resolution: {integrity: sha512-dJvrYWxP/UcXm36Qn36fxhUKu8A/xMRXVT2cliFF1Z7UA9liG5Psj3ezNSZw+5puH2czDXRLcXQxf8JbJt0ejg==} dev: true - /@types/node@20.11.2: - resolution: {integrity: sha512-cZShBaVa+UO1LjWWBPmWRR4+/eY/JR/UIEcDlVsw3okjWEu+rB7/mH6X3B/L+qJVHDLjk9QW/y2upp9wp1yDXA==} + /@types/node@20.11.24: + resolution: {integrity: sha512-Kza43ewS3xoLgCEpQrsT+xRo/EJej1y0kVYGiLFE1NEODXGzTfwiC6tXTLMQskn1X4/Rjlh0MQUvx9W+L9long==} dependencies: undici-types: 5.26.5 dev: true @@ -1193,8 +1193,8 @@ packages: resolution: {integrity: sha512-37i+OaWTh9qeK4LSHPsyRC7NahnGotNuZvjLSgcPzblpHB3rrCJxAOgI5gCdKm7coonsaX1Of0ILiTcnZjbfxA==} dev: true - /@types/semver@7.5.6: - resolution: {integrity: sha512-dn1l8LaMea/IjDoHNd9J52uBbInB796CDffS6VdIxvqYCPSG0V0DzHp76GpaWnlhg88uYyPbXCDIowa86ybd5A==} + /@types/semver@7.5.8: + resolution: {integrity: sha512-I8EUhyrgfLrcTkzV3TSsGyl1tSuPrEDzr0yd5m90UgNxQkyDXULk3b6MlQqTCpZpNtWe1K0hzclnZkTcLBe2UQ==} dev: true /@types/stack-utils@2.0.3: @@ -1222,7 +1222,7 @@ packages: /@types/ws@8.5.10: resolution: {integrity: sha512-vmQSUcfalpIq0R9q7uTo2lXs6eGIpt9wtnLdMv9LVpIjCA/+ufZRozlVoVelIYixx1ugCBKDhn89vnsEGOCx9A==} dependencies: - '@types/node': 20.11.2 + '@types/node': 20.11.24 dev: true /@types/yargs-parser@21.0.3: @@ -1239,12 +1239,12 @@ packages: resolution: {integrity: sha512-oJoftv0LSuaDZE3Le4DbKX+KS9G36NzOeSap90UIK0yMA/NhKJhqlSGtNDORNRaIbQfzjXDrQa0ytJ6mNRGz/Q==} requiresBuild: true dependencies: - '@types/node': 20.11.2 + '@types/node': 20.11.24 dev: true optional: true - /@typescript-eslint/eslint-plugin@6.19.0(@typescript-eslint/parser@6.19.0)(eslint@8.56.0)(typescript@5.1.6): - resolution: {integrity: sha512-DUCUkQNklCQYnrBSSikjVChdc84/vMPDQSgJTHBZ64G9bA9w0Crc0rd2diujKbTdp6w2J47qkeHQLoi0rpLCdg==} + /@typescript-eslint/eslint-plugin@6.21.0(@typescript-eslint/parser@6.21.0)(eslint@8.57.0)(typescript@5.1.6): + resolution: {integrity: sha512-oy9+hTPCUFpngkEZUSzbf9MxI65wbKFoQYsgPdILTfbUldp5ovUuphZVe4i30emU9M/kP+T64Di0mxl7dSw3MA==} engines: {node: ^16.0.0 || >=18.0.0} peerDependencies: '@typescript-eslint/parser': ^6.0.0 || ^6.0.0-alpha @@ -1255,25 +1255,25 @@ packages: optional: true dependencies: '@eslint-community/regexpp': 4.10.0 - '@typescript-eslint/parser': 6.19.0(eslint@8.56.0)(typescript@5.1.6) - '@typescript-eslint/scope-manager': 6.19.0 - '@typescript-eslint/type-utils': 6.19.0(eslint@8.56.0)(typescript@5.1.6) - '@typescript-eslint/utils': 6.19.0(eslint@8.56.0)(typescript@5.1.6) - '@typescript-eslint/visitor-keys': 6.19.0 + '@typescript-eslint/parser': 6.21.0(eslint@8.57.0)(typescript@5.1.6) + '@typescript-eslint/scope-manager': 6.21.0 + '@typescript-eslint/type-utils': 6.21.0(eslint@8.57.0)(typescript@5.1.6) + '@typescript-eslint/utils': 6.21.0(eslint@8.57.0)(typescript@5.1.6) + '@typescript-eslint/visitor-keys': 6.21.0 debug: 4.3.4(supports-color@8.1.1) - eslint: 8.56.0 + eslint: 8.57.0 graphemer: 1.4.0 - ignore: 5.3.0 + ignore: 5.3.1 natural-compare: 1.4.0 - semver: 7.5.4 - ts-api-utils: 1.0.3(typescript@5.1.6) + semver: 7.6.0 + ts-api-utils: 1.2.1(typescript@5.1.6) typescript: 5.1.6 transitivePeerDependencies: - supports-color dev: true - /@typescript-eslint/parser@6.19.0(eslint@8.56.0)(typescript@5.1.6): - resolution: {integrity: sha512-1DyBLG5SH7PYCd00QlroiW60YJ4rWMuUGa/JBV0iZuqi4l4IK3twKPq5ZkEebmGqRjXWVgsUzfd3+nZveewgow==} + /@typescript-eslint/parser@6.21.0(eslint@8.57.0)(typescript@5.1.6): + resolution: {integrity: sha512-tbsV1jPne5CkFQCgPBcDOt30ItF7aJoZL997JSF7MhGQqOeT3svWRYxiqlfA5RUdlHN6Fi+EI9bxqbdyAUZjYQ==} engines: {node: ^16.0.0 || >=18.0.0} peerDependencies: eslint: ^7.0.0 || ^8.0.0 @@ -1282,27 +1282,27 @@ packages: typescript: optional: true dependencies: - '@typescript-eslint/scope-manager': 6.19.0 - '@typescript-eslint/types': 6.19.0 - '@typescript-eslint/typescript-estree': 6.19.0(typescript@5.1.6) - '@typescript-eslint/visitor-keys': 6.19.0 + '@typescript-eslint/scope-manager': 6.21.0 + '@typescript-eslint/types': 6.21.0 + '@typescript-eslint/typescript-estree': 6.21.0(typescript@5.1.6) + '@typescript-eslint/visitor-keys': 6.21.0 debug: 4.3.4(supports-color@8.1.1) - eslint: 8.56.0 + eslint: 8.57.0 typescript: 5.1.6 transitivePeerDependencies: - supports-color dev: true - /@typescript-eslint/scope-manager@6.19.0: - resolution: {integrity: sha512-dO1XMhV2ehBI6QN8Ufi7I10wmUovmLU0Oru3n5LVlM2JuzB4M+dVphCPLkVpKvGij2j/pHBWuJ9piuXx+BhzxQ==} + /@typescript-eslint/scope-manager@6.21.0: + resolution: {integrity: sha512-OwLUIWZJry80O99zvqXVEioyniJMa+d2GrqpUTqi5/v5D5rOrppJVBPa0yKCblcigC0/aYAzxxqQ1B+DS2RYsg==} engines: {node: ^16.0.0 || >=18.0.0} dependencies: - '@typescript-eslint/types': 6.19.0 - '@typescript-eslint/visitor-keys': 6.19.0 + '@typescript-eslint/types': 6.21.0 + '@typescript-eslint/visitor-keys': 6.21.0 dev: true - /@typescript-eslint/type-utils@6.19.0(eslint@8.56.0)(typescript@5.1.6): - resolution: {integrity: sha512-mcvS6WSWbjiSxKCwBcXtOM5pRkPQ6kcDds/juxcy/727IQr3xMEcwr/YLHW2A2+Fp5ql6khjbKBzOyjuPqGi/w==} + /@typescript-eslint/type-utils@6.21.0(eslint@8.57.0)(typescript@5.1.6): + resolution: {integrity: sha512-rZQI7wHfao8qMX3Rd3xqeYSMCL3SoiSQLBATSiVKARdFGCYSRvmViieZjqc58jKgs8Y8i9YvVVhRbHSTA4VBag==} engines: {node: ^16.0.0 || >=18.0.0} peerDependencies: eslint: ^7.0.0 || ^8.0.0 @@ -1311,23 +1311,23 @@ packages: typescript: optional: true dependencies: - '@typescript-eslint/typescript-estree': 6.19.0(typescript@5.1.6) - '@typescript-eslint/utils': 6.19.0(eslint@8.56.0)(typescript@5.1.6) + '@typescript-eslint/typescript-estree': 6.21.0(typescript@5.1.6) + '@typescript-eslint/utils': 6.21.0(eslint@8.57.0)(typescript@5.1.6) debug: 4.3.4(supports-color@8.1.1) - eslint: 8.56.0 - ts-api-utils: 1.0.3(typescript@5.1.6) + eslint: 8.57.0 + ts-api-utils: 1.2.1(typescript@5.1.6) typescript: 5.1.6 transitivePeerDependencies: - supports-color dev: true - /@typescript-eslint/types@6.19.0: - resolution: {integrity: sha512-lFviGV/vYhOy3m8BJ/nAKoAyNhInTdXpftonhWle66XHAtT1ouBlkjL496b5H5hb8dWXHwtypTqgtb/DEa+j5A==} + /@typescript-eslint/types@6.21.0: + resolution: {integrity: sha512-1kFmZ1rOm5epu9NZEZm1kckCDGj5UJEf7P1kliH4LKu/RkwpsfqqGmY2OOcUs18lSlQBKLDYBOGxRVtrMN5lpg==} engines: {node: ^16.0.0 || >=18.0.0} dev: true - /@typescript-eslint/typescript-estree@6.19.0(typescript@5.1.6): - resolution: {integrity: sha512-o/zefXIbbLBZ8YJ51NlkSAt2BamrK6XOmuxSR3hynMIzzyMY33KuJ9vuMdFSXW+H0tVvdF9qBPTHA91HDb4BIQ==} + /@typescript-eslint/typescript-estree@6.21.0(typescript@5.1.6): + resolution: {integrity: sha512-6npJTkZcO+y2/kr+z0hc4HwNfrrP4kNYh57ek7yCNlrBjWQ1Y0OS7jiZTkgumrvkX5HkEKXFZkkdFNkaW2wmUQ==} engines: {node: ^16.0.0 || >=18.0.0} peerDependencies: typescript: '*' @@ -1335,43 +1335,43 @@ packages: typescript: optional: true dependencies: - '@typescript-eslint/types': 6.19.0 - '@typescript-eslint/visitor-keys': 6.19.0 + '@typescript-eslint/types': 6.21.0 + '@typescript-eslint/visitor-keys': 6.21.0 debug: 4.3.4(supports-color@8.1.1) globby: 11.1.0 is-glob: 4.0.3 minimatch: 9.0.3 - semver: 7.5.4 - ts-api-utils: 1.0.3(typescript@5.1.6) + semver: 7.6.0 + ts-api-utils: 1.2.1(typescript@5.1.6) typescript: 5.1.6 transitivePeerDependencies: - supports-color dev: true - /@typescript-eslint/utils@6.19.0(eslint@8.56.0)(typescript@5.1.6): - resolution: {integrity: sha512-QR41YXySiuN++/dC9UArYOg4X86OAYP83OWTewpVx5ct1IZhjjgTLocj7QNxGhWoTqknsgpl7L+hGygCO+sdYw==} + /@typescript-eslint/utils@6.21.0(eslint@8.57.0)(typescript@5.1.6): + resolution: {integrity: sha512-NfWVaC8HP9T8cbKQxHcsJBY5YE1O33+jpMwN45qzWWaPDZgLIbo12toGMWnmhvCpd3sIxkpDw3Wv1B3dYrbDQQ==} engines: {node: ^16.0.0 || >=18.0.0} peerDependencies: eslint: ^7.0.0 || ^8.0.0 dependencies: - '@eslint-community/eslint-utils': 4.4.0(eslint@8.56.0) + '@eslint-community/eslint-utils': 4.4.0(eslint@8.57.0) '@types/json-schema': 7.0.15 - '@types/semver': 7.5.6 - '@typescript-eslint/scope-manager': 6.19.0 - '@typescript-eslint/types': 6.19.0 - '@typescript-eslint/typescript-estree': 6.19.0(typescript@5.1.6) - eslint: 8.56.0 - semver: 7.5.4 + '@types/semver': 7.5.8 + '@typescript-eslint/scope-manager': 6.21.0 + '@typescript-eslint/types': 6.21.0 + '@typescript-eslint/typescript-estree': 6.21.0(typescript@5.1.6) + eslint: 8.57.0 + semver: 7.6.0 transitivePeerDependencies: - supports-color - typescript dev: true - /@typescript-eslint/visitor-keys@6.19.0: - resolution: {integrity: sha512-hZaUCORLgubBvtGpp1JEFEazcuEdfxta9j4iUwdSAr7mEsYYAp3EAUyCZk3VEEqGj6W+AV4uWyrDGtrlawAsgQ==} + /@typescript-eslint/visitor-keys@6.21.0: + resolution: {integrity: sha512-JJtkDduxLi9bivAB+cYOVMtbkqdPOhZ+ZI5LC47MIRrDV4Yn2o+ZnW10Nkmr28xRpSpdJ6Sm42Hjf2+REYXm0A==} engines: {node: ^16.0.0 || >=18.0.0} dependencies: - '@typescript-eslint/types': 6.19.0 + '@typescript-eslint/types': 6.21.0 eslint-visitor-keys: 3.4.3 dev: true @@ -1379,23 +1379,32 @@ packages: resolution: {integrity: sha512-zuVdFrMJiuCDQUMCzQaD6KL28MjnqqN8XnAqiEq9PNm/hCPTSGfrXCOfwj1ow4LFb/tNymJPwsNbVePc1xFqrQ==} dev: true - /@wdio/cli@8.27.2(typescript@5.1.6): - resolution: {integrity: sha512-gRbwqjjczReWqLFZQX9iwTsCwGPFavJwL7iKSoIeAS645sM9PMmPW7mHzawmkFxqDDAyBWO3qFn4KV2H/2YfdA==} + /@vitest/snapshot@1.3.1: + resolution: {integrity: sha512-EF++BZbt6RZmOlE3SuTPu/NfwBF6q4ABS37HHXzs2LUVPBLx2QoY/K0fKpRChSo8eLiuxcbCVfqKgx/dplCDuQ==} + dependencies: + magic-string: 0.30.7 + pathe: 1.1.2 + pretty-format: 29.7.0 + dev: true + + /@wdio/cli@8.32.3(typescript@5.1.6): + resolution: {integrity: sha512-qjR1MFKQM547iCooceBHyggJRNguD7fhgF4Q7L2r7psG3AQFWzdCN/8rulRGIxTz4PJlIqks9AH9kUJlVAf44A==} engines: {node: ^16.13 || >=18} hasBin: true dependencies: - '@types/node': 20.11.2 - '@wdio/config': 8.27.2 - '@wdio/globals': 8.27.2(typescript@5.1.6) - '@wdio/logger': 8.24.12 - '@wdio/protocols': 8.24.12 - '@wdio/types': 8.27.2 - '@wdio/utils': 8.27.2 + '@types/node': 20.11.24 + '@vitest/snapshot': 1.3.1 + '@wdio/config': 8.32.3 + '@wdio/globals': 8.32.3(typescript@5.1.6) + '@wdio/logger': 8.28.0 + '@wdio/protocols': 8.32.0 + '@wdio/types': 8.32.2 + '@wdio/utils': 8.32.3 async-exit-hook: 2.0.1 chalk: 5.3.0 - chokidar: 3.5.3 + chokidar: 3.6.0 cli-spinners: 2.9.2 - dotenv: 16.3.1 + dotenv: 16.4.5 ejs: 3.1.9 execa: 8.0.1 import-meta-resolve: 4.0.0 @@ -1403,9 +1412,9 @@ packages: lodash.flattendeep: 4.4.0 lodash.pickby: 4.6.0 lodash.union: 4.6.0 - read-pkg-up: 10.1.0 + read-pkg-up: 10.0.0 recursive-readdir: 2.2.3 - webdriverio: 8.27.2(typescript@5.1.6) + webdriverio: 8.32.3(typescript@5.1.6) yargs: 17.7.2 transitivePeerDependencies: - bufferutil @@ -1416,13 +1425,13 @@ packages: - utf-8-validate dev: true - /@wdio/config@8.27.2: - resolution: {integrity: sha512-qR1r7K7/jsQhi9g5NiW40lgbvbzCcwwk8nz07hzTj6m8fQ8TXkQPob2fnrlDaNrXjzbZC4od0uv0a5fimK9YOQ==} + /@wdio/config@8.32.3: + resolution: {integrity: sha512-hZkaz5Fd8830uniQvRgPus8yp9rp50MAsHa5kZ2Jt8y++Rp330FyJpQZE5oPjTATuz35G5Anprk2Q3fmFd0Ifw==} engines: {node: ^16.13 || >=18} dependencies: - '@wdio/logger': 8.24.12 - '@wdio/types': 8.27.2 - '@wdio/utils': 8.27.2 + '@wdio/logger': 8.28.0 + '@wdio/types': 8.32.2 + '@wdio/utils': 8.32.3 decamelize: 6.0.0 deepmerge-ts: 5.1.0 glob: 10.3.10 @@ -1431,12 +1440,12 @@ packages: - supports-color dev: true - /@wdio/globals@8.27.2(typescript@5.1.6): - resolution: {integrity: sha512-kU9fsOD1HVSROgN0TkjH8+O2SWbd5hHzL952+YOifMHFtt05Ua/n5mqxTTVAWmxUMMCz6VOuySmBt2Dhd4NnKA==} + /@wdio/globals@8.32.3(typescript@5.1.6): + resolution: {integrity: sha512-jyK89GvWaOYQT9pfZ6HNwkFANgai9eBVfeDPw5yFLXfk6js9GSWbvqMJg/PFi1dQ7xbnbuuf5eYVc65bfAt9KQ==} engines: {node: ^16.13 || >=18} optionalDependencies: - expect-webdriverio: 4.8.1(typescript@5.1.6) - webdriverio: 8.27.2(typescript@5.1.6) + expect-webdriverio: 4.11.9(typescript@5.1.6) + webdriverio: 8.32.3(typescript@5.1.6) transitivePeerDependencies: - bufferutil - devtools @@ -1446,15 +1455,15 @@ packages: - utf-8-validate dev: true - /@wdio/local-runner@8.27.2(typescript@5.1.6): - resolution: {integrity: sha512-7m0vEulOyriMPB1+559ioEdjXlLu7yseM3KfQapCdLqaqTWvURJlMSxiHZZwuHaVGKa6YBPNB7NhRcHoUsqsAg==} + /@wdio/local-runner@8.32.3(typescript@5.1.6): + resolution: {integrity: sha512-YgqYkKarx2m9OjA8WO4NqQPCfFNLmZHnuEWQ6P2LqUeYFsdXRd3wR3UTo9XrI23VSQo+kcpqInsR5vLOYDd1zg==} engines: {node: ^16.13 || >=18} dependencies: - '@types/node': 20.11.2 - '@wdio/logger': 8.24.12 + '@types/node': 20.11.24 + '@wdio/logger': 8.28.0 '@wdio/repl': 8.24.12 - '@wdio/runner': 8.27.2(typescript@5.1.6) - '@wdio/types': 8.27.2 + '@wdio/runner': 8.32.3(typescript@5.1.6) + '@wdio/types': 8.32.2 async-exit-hook: 2.0.1 split2: 4.2.0 stream-buffers: 3.0.2 @@ -1467,67 +1476,67 @@ packages: - utf-8-validate dev: true - /@wdio/logger@8.24.12: - resolution: {integrity: sha512-QisOiVIWKTUCf1H7S+DOtC+gruhlpimQrUXfWMTeeh672PvAJYnTpOJDWA+BtXfsikkUYFAzAaq8SeMJk8rqKg==} + /@wdio/logger@8.28.0: + resolution: {integrity: sha512-/s6zNCqwy1hoc+K4SJypis0Ud0dlJ+urOelJFO1x0G0rwDRWyFiUP6ijTaCcFxAm29jYEcEPWijl2xkVIHwOyA==} engines: {node: ^16.13 || >=18} dependencies: chalk: 5.3.0 - loglevel: 1.8.1 + loglevel: 1.9.1 loglevel-plugin-prefix: 0.8.4 strip-ansi: 7.1.0 dev: true - /@wdio/mocha-framework@8.27.2: - resolution: {integrity: sha512-R0PRW5X8VDJzpHPhtOGkcPFrcetDOYz9q//4uqvdtdKtngrp4goz2cVNEmnbXJDMUm5VHSYy2GW6YtsjWUxbkA==} + /@wdio/mocha-framework@8.32.3: + resolution: {integrity: sha512-wwQ6rDd6TMPqwGfkwvtcBmcirYZUi9GUiwH2OsHvMJ4i+YY7H2dLyZon1ghcIan7r4ufr8KlljbwyerCpUzvcw==} engines: {node: ^16.13 || >=18} dependencies: '@types/mocha': 10.0.6 - '@types/node': 20.11.2 - '@wdio/logger': 8.24.12 - '@wdio/types': 8.27.2 - '@wdio/utils': 8.27.2 - mocha: 10.2.0 + '@types/node': 20.11.24 + '@wdio/logger': 8.28.0 + '@wdio/types': 8.32.2 + '@wdio/utils': 8.32.3 + mocha: 10.3.0 transitivePeerDependencies: - supports-color dev: true - /@wdio/protocols@8.24.12: - resolution: {integrity: sha512-QnVj3FkapmVD3h2zoZk+ZQ8gevSj9D9MiIQIy8eOnY4FAneYZ9R9GvoW+mgNcCZO8S8++S/jZHetR8n+8Q808g==} + /@wdio/protocols@8.32.0: + resolution: {integrity: sha512-inLJRrtIGdTz/YPbcsvpSvPlYQFTVtF3OYBwAXhG2FiP1ZwE1CQNLP/xgRGye1ymdGCypGkexRqIx3KBGm801Q==} dev: true /@wdio/repl@8.24.12: resolution: {integrity: sha512-321F3sWafnlw93uRTSjEBVuvWCxTkWNDs7ektQS15drrroL3TMeFOynu4rDrIz0jXD9Vas0HCD2Tq/P0uxFLdw==} engines: {node: ^16.13 || >=18} dependencies: - '@types/node': 20.11.2 + '@types/node': 20.11.24 dev: true - /@wdio/reporter@8.27.2: - resolution: {integrity: sha512-vMhoTVsowDmk6EXYgJ4nFBd6vvMFLIO3zUL4w/DCCkPDyjS9/6ggs/wpVSlrKxw9qisAph1Z4W9ngtNuhQQuwg==} + /@wdio/reporter@8.32.2: + resolution: {integrity: sha512-BZdReAFfRCtgtYbyhkKgSGqqoIn/yG5/Z4COjvRvon9NJkz+eA4PiHCKdEP7+ekBIjud7H8Gy+6mPBDEu+wllw==} engines: {node: ^16.13 || >=18} dependencies: - '@types/node': 20.11.2 - '@wdio/logger': 8.24.12 - '@wdio/types': 8.27.2 - diff: 5.1.0 + '@types/node': 20.11.24 + '@wdio/logger': 8.28.0 + '@wdio/types': 8.32.2 + diff: 5.2.0 object-inspect: 1.13.1 dev: true - /@wdio/runner@8.27.2(typescript@5.1.6): - resolution: {integrity: sha512-a72dJ+7ap0DOrkrjx1ofYHzgDYzK0I7RjSGOEvi2cc+SwnwESHnwtPug5F3NfDFEMXV3Y3pN+E/yz81S27WpvQ==} + /@wdio/runner@8.32.3(typescript@5.1.6): + resolution: {integrity: sha512-HlhdQ4lJ07seL7/x0UQPDnK+o5a0okyjd8ukFYqDL+g9+d3KlW/oM3NvFfX7pb9liIYNEpmoNMwKFp+5XPUE7w==} engines: {node: ^16.13 || >=18} dependencies: - '@types/node': 20.11.2 - '@wdio/config': 8.27.2 - '@wdio/globals': 8.27.2(typescript@5.1.6) - '@wdio/logger': 8.24.12 - '@wdio/types': 8.27.2 - '@wdio/utils': 8.27.2 + '@types/node': 20.11.24 + '@wdio/config': 8.32.3 + '@wdio/globals': 8.32.3(typescript@5.1.6) + '@wdio/logger': 8.28.0 + '@wdio/types': 8.32.2 + '@wdio/utils': 8.32.3 deepmerge-ts: 5.1.0 - expect-webdriverio: 4.8.1(typescript@5.1.6) + expect-webdriverio: 4.11.9(typescript@5.1.6) gaze: 1.1.3 - webdriver: 8.27.2 - webdriverio: 8.27.2(typescript@5.1.6) + webdriver: 8.32.3 + webdriverio: 8.32.3(typescript@5.1.6) transitivePeerDependencies: - bufferutil - devtools @@ -1537,38 +1546,38 @@ packages: - utf-8-validate dev: true - /@wdio/spec-reporter@8.27.2: - resolution: {integrity: sha512-2U1MALAHjUqDo3C+PYinN1wAnDBiy+kLG3GrTpMeIWZ2qZ6m1fRWt9GlADX7r07vhiRqShxy131nUenqeoF/qg==} + /@wdio/spec-reporter@8.32.2: + resolution: {integrity: sha512-3hUXpE+idC4KOXofJnpubdDDCE8X0OTd6ykypiaXMI2hJTA2nIZcHtpRQnAE0E4JT9OzLnPWODcMq54GGBDRkg==} engines: {node: ^16.13 || >=18} dependencies: - '@wdio/reporter': 8.27.2 - '@wdio/types': 8.27.2 + '@wdio/reporter': 8.32.2 + '@wdio/types': 8.32.2 chalk: 5.3.0 easy-table: 1.2.0 pretty-ms: 7.0.1 dev: true - /@wdio/types@8.27.2: - resolution: {integrity: sha512-z/TtSQysEtAUNh+DooOs22G7xotTsJC2RcIZKaVtHY4Gl6lF+tn8kLRXD79jem2ta1byB1TpW62K366k1vzcLw==} + /@wdio/types@8.32.2: + resolution: {integrity: sha512-jq8LcBBQpBP9ZF5kECKEpXv8hN7irCGCjLFAN0Bd5ScRR6qu6MGWvwkDkau2sFPr0b++sKDCEaMzQlwrGFjZXg==} engines: {node: ^16.13 || >=18} dependencies: - '@types/node': 20.11.2 + '@types/node': 20.11.24 dev: true - /@wdio/utils@8.27.2: - resolution: {integrity: sha512-jWxUhGjlZ4L3uOsP96oLKWjkITpoH/KPTtKzU7xdoVGhd1LXK4d/Fr8cTFTNkDBXM7yuM7C+EMmQ8HJHR55KTA==} + /@wdio/utils@8.32.3: + resolution: {integrity: sha512-UnR9rPpR1W9U5wz2TU+6BQ2rlxtuK/e3fvdaiWIMZKleB/OCcEQFGiGPAGGVi4ShfaTPwz6hK1cTTgj1OtMXkg==} engines: {node: ^16.13 || >=18} dependencies: '@puppeteer/browsers': 1.9.1 - '@wdio/logger': 8.24.12 - '@wdio/types': 8.27.2 + '@wdio/logger': 8.28.0 + '@wdio/types': 8.32.2 decamelize: 6.0.0 deepmerge-ts: 5.1.0 - edgedriver: 5.3.9 - geckodriver: 4.3.0 + edgedriver: 5.3.10 + geckodriver: 4.3.3 get-port: 7.0.0 import-meta-resolve: 4.0.0 - locate-app: 2.2.7 + locate-app: 2.2.20 safaridriver: 0.1.2 split2: 4.2.0 wait-port: 1.1.0 @@ -1700,8 +1709,8 @@ packages: readable-stream: 3.6.2 dev: true - /archiver@6.0.1: - resolution: {integrity: sha512-CXGy4poOLBKptiZH//VlWdFuUC1RESbdZjGjILwBuZ73P7WkAUN0htfSfBq/7k6FRFlpu7bg4JOkj1vU9G6jcQ==} + /archiver@6.0.2: + resolution: {integrity: sha512-UQ/2nW7NMl1G+1UnrLypQw1VdT9XZg/ECcKPq7l+STzStrSivFIXIp34D8M5zeNGW5NoOupdYCHv6VySCPNNlw==} engines: {node: '>= 12.0.0'} dependencies: archiver-utils: 4.0.1 @@ -1709,8 +1718,8 @@ packages: buffer-crc32: 0.2.13 readable-stream: 3.6.2 readdir-glob: 1.1.3 - tar-stream: 3.1.6 - zip-stream: 5.0.1 + tar-stream: 3.1.7 + zip-stream: 5.0.2 dev: true /argparse@1.0.10: @@ -1767,26 +1776,26 @@ packages: handlebars: 4.7.8 node-fetch: 2.7.0 parse-github-url: 1.0.2 - semver: 7.5.4 + semver: 7.6.0 transitivePeerDependencies: - encoding dev: true - /b4a@1.6.4: - resolution: {integrity: sha512-fpWrvyVHEKyeEvbKZTVOeZF3VSKKWtJxFIxX/jaVPf+cLbGUSitjb49pHLqPV2BUNNZ0LcoeEGfE/YCpyDYHIw==} + /b4a@1.6.6: + resolution: {integrity: sha512-5Tk1HLk6b6ctmjIkAcU/Ujv/1WqiDl0F0JdRCR80VsOcUlHcu7pWeWRlOqQLHfDEsVx9YH/aif5AG4ehoCtTmg==} dev: true - /babel-jest@29.7.0(@babel/core@7.23.7): + /babel-jest@29.7.0(@babel/core@7.24.0): resolution: {integrity: sha512-BrvGY3xZSwEcCzKvKsCi2GgHqDqsYkOP4/by5xCgIwGXQxIEh+8ew3gmrE1y7XRR6LHZIj6yLYnUi/mm2KXKBg==} engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} peerDependencies: '@babel/core': ^7.8.0 dependencies: - '@babel/core': 7.23.7 + '@babel/core': 7.24.0 '@jest/transform': 29.7.0 '@types/babel__core': 7.20.5 babel-plugin-istanbul: 6.1.1 - babel-preset-jest: 29.6.3(@babel/core@7.23.7) + babel-preset-jest: 29.6.3(@babel/core@7.24.0) chalk: 4.1.2 graceful-fs: 4.2.11 slash: 3.0.0 @@ -1798,7 +1807,7 @@ packages: resolution: {integrity: sha512-Y1IQok9821cC9onCx5otgFfRm7Lm+I+wwxOx738M/WLPZ9Q42m4IG5W0FNX8WLL2gYMZo3JkuXIH2DOpWM+qwA==} engines: {node: '>=8'} dependencies: - '@babel/helper-plugin-utils': 7.22.5 + '@babel/helper-plugin-utils': 7.24.0 '@istanbuljs/load-nyc-config': 1.1.0 '@istanbuljs/schema': 0.1.3 istanbul-lib-instrument: 5.2.1 @@ -1811,53 +1820,84 @@ packages: resolution: {integrity: sha512-ESAc/RJvGTFEzRwOTT4+lNDk/GNHMkKbNzsvT0qKRfDyyYTskxB5rnU2njIDYVxXCBHHEI1c0YwHob3WaYujOg==} engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} dependencies: - '@babel/template': 7.22.15 - '@babel/types': 7.23.6 + '@babel/template': 7.24.0 + '@babel/types': 7.24.0 '@types/babel__core': 7.20.5 '@types/babel__traverse': 7.20.5 dev: true - /babel-preset-current-node-syntax@1.0.1(@babel/core@7.23.7): + /babel-preset-current-node-syntax@1.0.1(@babel/core@7.24.0): resolution: {integrity: sha512-M7LQ0bxarkxQoN+vz5aJPsLBn77n8QgTFmo8WK0/44auK2xlCXrYcUxHFxgU7qW5Yzw/CjmLRK2uJzaCd7LvqQ==} peerDependencies: '@babel/core': ^7.0.0 dependencies: - '@babel/core': 7.23.7 - '@babel/plugin-syntax-async-generators': 7.8.4(@babel/core@7.23.7) - '@babel/plugin-syntax-bigint': 7.8.3(@babel/core@7.23.7) - '@babel/plugin-syntax-class-properties': 7.12.13(@babel/core@7.23.7) - '@babel/plugin-syntax-import-meta': 7.10.4(@babel/core@7.23.7) - '@babel/plugin-syntax-json-strings': 7.8.3(@babel/core@7.23.7) - '@babel/plugin-syntax-logical-assignment-operators': 7.10.4(@babel/core@7.23.7) - '@babel/plugin-syntax-nullish-coalescing-operator': 7.8.3(@babel/core@7.23.7) - '@babel/plugin-syntax-numeric-separator': 7.10.4(@babel/core@7.23.7) - '@babel/plugin-syntax-object-rest-spread': 7.8.3(@babel/core@7.23.7) - '@babel/plugin-syntax-optional-catch-binding': 7.8.3(@babel/core@7.23.7) - '@babel/plugin-syntax-optional-chaining': 7.8.3(@babel/core@7.23.7) - '@babel/plugin-syntax-top-level-await': 7.14.5(@babel/core@7.23.7) - dev: true - - /babel-preset-jest@29.6.3(@babel/core@7.23.7): + '@babel/core': 7.24.0 + '@babel/plugin-syntax-async-generators': 7.8.4(@babel/core@7.24.0) + '@babel/plugin-syntax-bigint': 7.8.3(@babel/core@7.24.0) + '@babel/plugin-syntax-class-properties': 7.12.13(@babel/core@7.24.0) + '@babel/plugin-syntax-import-meta': 7.10.4(@babel/core@7.24.0) + '@babel/plugin-syntax-json-strings': 7.8.3(@babel/core@7.24.0) + '@babel/plugin-syntax-logical-assignment-operators': 7.10.4(@babel/core@7.24.0) + '@babel/plugin-syntax-nullish-coalescing-operator': 7.8.3(@babel/core@7.24.0) + '@babel/plugin-syntax-numeric-separator': 7.10.4(@babel/core@7.24.0) + '@babel/plugin-syntax-object-rest-spread': 7.8.3(@babel/core@7.24.0) + '@babel/plugin-syntax-optional-catch-binding': 7.8.3(@babel/core@7.24.0) + '@babel/plugin-syntax-optional-chaining': 7.8.3(@babel/core@7.24.0) + '@babel/plugin-syntax-top-level-await': 7.14.5(@babel/core@7.24.0) + dev: true + + /babel-preset-jest@29.6.3(@babel/core@7.24.0): resolution: {integrity: sha512-0B3bhxR6snWXJZtR/RliHTDPRgn1sNHOR0yVtq/IiQFyuOVjFS+wuio/R4gSNkyYmKmJB4wGZv2NZanmKmTnNA==} engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} peerDependencies: '@babel/core': ^7.0.0 dependencies: - '@babel/core': 7.23.7 + '@babel/core': 7.24.0 babel-plugin-jest-hoist: 29.6.3 - babel-preset-current-node-syntax: 1.0.1(@babel/core@7.23.7) + babel-preset-current-node-syntax: 1.0.1(@babel/core@7.24.0) dev: true /balanced-match@1.0.2: resolution: {integrity: sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==} dev: true + /bare-events@2.2.1: + resolution: {integrity: sha512-9GYPpsPFvrWBkelIhOhTWtkeZxVxZOdb3VnFTCzlOo3OjvmTvzLoZFUT8kNFACx0vJej6QPney1Cf9BvzCNE/A==} + requiresBuild: true + dev: true + optional: true + + /bare-fs@2.2.1: + resolution: {integrity: sha512-+CjmZANQDFZWy4PGbVdmALIwmt33aJg8qTkVjClU6X4WmZkTPBDxRHiBn7fpqEWEfF3AC2io++erpViAIQbSjg==} + requiresBuild: true + dependencies: + bare-events: 2.2.1 + bare-os: 2.2.0 + bare-path: 2.1.0 + streamx: 2.16.1 + dev: true + optional: true + + /bare-os@2.2.0: + resolution: {integrity: sha512-hD0rOPfYWOMpVirTACt4/nK8mC55La12K5fY1ij8HAdfQakD62M+H4o4tpfKzVGLgRDTuk3vjA4GqGXXCeFbag==} + requiresBuild: true + dev: true + optional: true + + /bare-path@2.1.0: + resolution: {integrity: sha512-DIIg7ts8bdRKwJRJrUMy/PICEaQZaPGZ26lsSx9MJSwIhSrcdHn7/C8W+XmnG/rKi6BaRcz+JO00CjZteybDtw==} + requiresBuild: true + dependencies: + bare-os: 2.2.0 + dev: true + optional: true + /base64-js@1.5.1: resolution: {integrity: sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA==} dev: true - /basic-ftp@5.0.4: - resolution: {integrity: sha512-8PzkB0arJFV4jJWSGOYR+OEic6aeKMu/osRhBULN6RY0ykby6LKhbmuQ5ublvaas5BOwboah5D87nrHyuh8PPA==} + /basic-ftp@5.0.5: + resolution: {integrity: sha512-4Bcg1P8xhUuqcii/S0Z9wiHIrQVPMermM1any+MX5GeGD7faD3/msQUDGLol9wOcz4/jbg/WJnGqoJF6LiBdtg==} engines: {node: '>=10.0.0'} dev: true @@ -1914,15 +1954,15 @@ packages: resolution: {integrity: sha512-qhAVI1+Av2X7qelOfAIYwXONood6XlZE/fXaBSmW/T5SzLAmCgzi+eiWE7fUvbHaeNBQH13UftjpXxsfLkMpgw==} dev: true - /browserslist@4.22.2: - resolution: {integrity: sha512-0UgcrvQmBDvZHFGdYUehrCNIazki7/lUP3kkoi/r3YB2amZbFM9J43ZRkJTXBUZK4gmx56+Sqk9+Vs9mwZx9+A==} + /browserslist@4.23.0: + resolution: {integrity: sha512-QW8HiM1shhT2GuzkvklfjcKDiWFXHOeFCIA/huJPwHsslwcydgk7X+z2zXpEijP98UCY7HbubZt5J2Zgvf0CaQ==} engines: {node: ^6 || ^7 || ^8 || ^9 || ^10 || ^11 || ^12 || >=13.7} hasBin: true dependencies: - caniuse-lite: 1.0.30001576 - electron-to-chromium: 1.4.630 + caniuse-lite: 1.0.30001591 + electron-to-chromium: 1.4.690 node-releases: 2.0.14 - update-browserslist-db: 1.0.13(browserslist@4.22.2) + update-browserslist-db: 1.0.13(browserslist@4.23.0) dev: true /bs-logger@0.2.6: @@ -1986,12 +2026,15 @@ packages: responselike: 3.0.0 dev: true - /call-bind@1.0.5: - resolution: {integrity: sha512-C3nQxfFZxFRVoJoGKKI8y3MOEo129NQ+FgQ08iye+Mk4zNZZGdjfs06bVTr+DBSlA66Q2VEcMki/cUCP4SercQ==} + /call-bind@1.0.7: + resolution: {integrity: sha512-GHTSNSYICQ7scH7sZ+M2rFopRoLh8t2bLSW6BbgrtLsahOIB5iyAVJf9GjWK3cYTDaMj4XdBpM1cA6pIS0Kv2w==} + engines: {node: '>= 0.4'} dependencies: + es-define-property: 1.0.0 + es-errors: 1.3.0 function-bind: 1.1.2 - get-intrinsic: 1.2.2 - set-function-length: 1.2.0 + get-intrinsic: 1.2.4 + set-function-length: 1.2.1 dev: true /callsites@3.1.0: @@ -2009,8 +2052,8 @@ packages: engines: {node: '>=10'} dev: true - /caniuse-lite@1.0.30001576: - resolution: {integrity: sha512-ff5BdakGe2P3SQsMsiqmt1Lc8221NR1VzHj5jXN5vBny9A6fpze94HiVV/n7XRosOlsShJcvMv5mdnpjOGCEgg==} + /caniuse-lite@1.0.30001591: + resolution: {integrity: sha512-PCzRMei/vXjJyL5mJtzNiUCKP59dm8Apqc3PH8gJkMnMXZGox93RbE76jHsmLwmIo6/3nsYIpJtx0O7u5PqFuQ==} dev: true /chai@4.4.1: @@ -2063,9 +2106,9 @@ packages: resolution: {integrity: sha512-mT8iDcrh03qDGRRmoA2hmBJnxpllMR+0/0qlzjqZES6NdiWDcZkCNAk4rPFZ9Q85r27unkiNNg8ZOiwZXBHwcA==} dev: true - /chart.js@4.4.1: - resolution: {integrity: sha512-C74QN1bxwV1v2PEujhmKjOZ7iUM4w6BWs23Md/6aOZZSlwMzeCIDGuZay++rBgChYru7/+QFeoQW0fQoP534Dg==} - engines: {pnpm: '>=7'} + /chart.js@4.4.2: + resolution: {integrity: sha512-6GD7iKwFpP5kbSD4MeRRRlTnQvxfQREy36uEtm1hzHzcOqwWx0YEHuspuoNlslu+nciLIB7fjjsHkUv/FzFcOg==} + engines: {pnpm: '>=8'} dependencies: '@kurkle/color': 0.3.2 dev: false @@ -2091,6 +2134,21 @@ packages: fsevents: 2.3.3 dev: true + /chokidar@3.6.0: + resolution: {integrity: sha512-7VT13fmjotKpGipCW9JEQAusEPE+Ei8nl6/g4FBAmIm0GOOLMua9NDDo/DWp0ZAxCr3cPq5ZpBqmPAQgDda2Pw==} + engines: {node: '>= 8.10.0'} + dependencies: + anymatch: 3.1.3 + braces: 3.0.2 + glob-parent: 5.1.2 + is-binary-path: 2.1.0 + is-glob: 4.0.3 + normalize-path: 3.0.0 + readdirp: 3.6.0 + optionalDependencies: + fsevents: 2.3.3 + dev: true + /chromium-bidi@0.4.16(devtools-protocol@0.0.1147663): resolution: {integrity: sha512-7ZbXdWERxRxSwo3txsBjjmc/NLxqb1Bk30mRb0BMS4YIaiV6zvKZqL/UAH+DdqcDYayDWk2n/y8klkBDODrPvA==} peerDependencies: @@ -2196,12 +2254,12 @@ packages: engines: {node: ^12.20.0 || >=14} dev: true - /compress-commons@5.0.1: - resolution: {integrity: sha512-MPh//1cERdLtqwO3pOFLeXtpuai0Y2WCd5AhtKxznqM7WtaMYaOEMSgn45d9D10sIHSfIKE603HlOp8OPGrvag==} + /compress-commons@5.0.3: + resolution: {integrity: sha512-/UIcLWvwAQyVibgpQDPtfNM3SvqN7G9elAPAV7GM0L53EbNWwWiCsWtK8Fwed/APEbptPHXs5PuW+y8Bq8lFTA==} engines: {node: '>= 12.0.0'} dependencies: crc-32: 1.2.2 - crc32-stream: 5.0.0 + crc32-stream: 5.0.1 normalize-path: 3.0.0 readable-stream: 3.6.2 dev: true @@ -2224,15 +2282,15 @@ packages: hasBin: true dev: true - /crc32-stream@5.0.0: - resolution: {integrity: sha512-B0EPa1UK+qnpBZpG+7FgPCu0J2ETLpXq09o9BkLkEAhdB6Z61Qo4pJ3JYu0c+Qi+/SAL7QThqnzS06pmSSyZaw==} + /crc32-stream@5.0.1: + resolution: {integrity: sha512-lO1dFui+CEUh/ztYIpgpKItKW9Bb4NWakCRJrnqAbFIYD+OZAwb2VfD5T5eXMw2FNcsDHkQcNl/Wh3iVXYwU6g==} engines: {node: '>= 12.0.0'} dependencies: crc-32: 1.2.2 readable-stream: 3.6.2 dev: true - /create-jest@29.7.0(@types/node@20.11.2): + /create-jest@29.7.0(@types/node@20.11.24): resolution: {integrity: sha512-Adz2bdH0Vq3F53KEMJOoftQFutWCukm6J24wbPWRO4k1kMY7gS7ds/uoJkNuV8wDCtWWnuwGcJwpWcih+zEW1Q==} engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} hasBin: true @@ -2241,7 +2299,7 @@ packages: chalk: 4.1.2 exit: 0.1.2 graceful-fs: 4.2.11 - jest-config: 29.7.0(@types/node@20.11.2) + jest-config: 29.7.0(@types/node@20.11.24) jest-util: 29.7.0 prompts: 2.4.2 transitivePeerDependencies: @@ -2296,8 +2354,8 @@ packages: engines: {node: '>= 12'} dev: true - /data-uri-to-buffer@6.0.1: - resolution: {integrity: sha512-MZd3VlchQkp8rdend6vrx7MmVDJzSNTBvghvKjirLkD+WTChA3KUf0jkE68Q4UyctNqI11zZO9/x2Yx+ub5Cvg==} + /data-uri-to-buffer@6.0.2: + resolution: {integrity: sha512-7hvf7/GW8e86rW0ptuwS3OcBGDjIi6SZva7hCyWC0yYry2cOPmLIjXAUHI6DK2HsnwJd9ifmt57i8eV2n4YNpw==} engines: {node: '>= 14'} dev: true @@ -2398,13 +2456,13 @@ packages: engines: {node: '>=10'} dev: true - /define-data-property@1.1.1: - resolution: {integrity: sha512-E7uGkTzkk1d0ByLeSc6ZsFS79Axg+m1P/VsgYsxHgiuc3tFSj+MjMIwe90FC4lOAZzNBdY7kkO2P2wKdsQ1vgQ==} + /define-data-property@1.1.4: + resolution: {integrity: sha512-rBMvIzlpA8v6E+SJZoo++HAYqsLrkg7MSfIinMPFhmkorw7X+dOXVJQs+QT69zGkzMyfDnIMN2Wid1+NbL3T+A==} engines: {node: '>= 0.4'} dependencies: - get-intrinsic: 1.2.2 + es-define-property: 1.0.0 + es-errors: 1.3.0 gopd: 1.0.1 - has-property-descriptors: 1.0.1 dev: true /degenerator@5.0.1: @@ -2435,8 +2493,8 @@ packages: resolution: {integrity: sha512-hyWmRrexdhbZ1tcJUGpO95ivbRhWXz++F4Ko+n21AY5PNln2ovoJw+8ZMNDTtip+CNFQfrtLVh/w4009dXO/eQ==} dev: true - /devtools-protocol@0.0.1239539: - resolution: {integrity: sha512-uS7hZVqZxGyZwR8lX/8wWyNLGEYs1wWWxN7qeRC+wBZ4VM5JXYwCJg8hofEna5yX0W2cavpjHOE4ukHXLHlEaA==} + /devtools-protocol@0.0.1262051: + resolution: {integrity: sha512-YJe4CT5SA8on3Spa+UDtNhEqtuV6Epwz3OZ4HQVLhlRccpZ9/PAYk0/cy/oKxFKRrZPBUPyxympQci4yWNWZ9g==} dev: true /diff-sequences@29.6.3: @@ -2449,8 +2507,8 @@ packages: engines: {node: '>=0.3.1'} dev: true - /diff@5.1.0: - resolution: {integrity: sha512-D+mk+qE8VC/PAUrlAU34N+VfXev0ghe5ywmpqrawphmVZc1bEfn56uo9qpyGp1p4xpzOHkSW4ztBd6L7Xx4ACw==} + /diff@5.2.0: + resolution: {integrity: sha512-uIFDxqpRZGZ6ThOk84hEfqWoHx2devRFvpTZcTHur85vImfaxUbTW9Ryh4CpCuDnToOP1CEtXKIgytHBPVff5A==} engines: {node: '>=0.3.1'} dev: true @@ -2476,8 +2534,8 @@ packages: webidl-conversions: 7.0.0 dev: true - /dotenv@16.3.1: - resolution: {integrity: sha512-IPzF4w4/Rd94bA9imS68tZBaYyBWSCE47V1RGuMrB94iyTOIEwRmVL2x/4An+6mETpLrKJ5hQkB8W4kFAadeIQ==} + /dotenv@16.4.5: + resolution: {integrity: sha512-ZmdL2rui+eB2YwhsWzjInR8LldtZHGDoQ1ugH85ppHKwpUHL7j7rN0Ti9NCnGiQbhaZ11FpR+7ao1dNsmduNUg==} engines: {node: '>=12'} dev: true @@ -2507,12 +2565,12 @@ packages: which: 2.0.2 dev: true - /edgedriver@5.3.9: - resolution: {integrity: sha512-G0wNgFMFRDnFfKaXG2R6HiyVHqhKwdQ3EgoxW3wPlns2wKqem7F+HgkWBcevN7Vz0nN4AXtskID7/6jsYDXcKw==} + /edgedriver@5.3.10: + resolution: {integrity: sha512-RFSHYMNtcF1PjaGZCA2rdQQ8hSTLPZgcYgeY1V6dC+tR4NhZXwFAku+8hCbRYh7ZlwKKrTbVu9FwknjFddIuuw==} hasBin: true requiresBuild: true dependencies: - '@wdio/logger': 8.24.12 + '@wdio/logger': 8.28.0 decamelize: 6.0.0 edge-paths: 3.0.5 node-fetch: 3.3.2 @@ -2528,8 +2586,8 @@ packages: jake: 10.8.7 dev: true - /electron-to-chromium@1.4.630: - resolution: {integrity: sha512-osHqhtjojpCsACVnuD11xO5g9xaCyw7Qqn/C2KParkMv42i8jrJJgx3g7mkHfpxwhy9MnOJr8+pKOdZ7qzgizg==} + /electron-to-chromium@1.4.690: + resolution: {integrity: sha512-+2OAGjUx68xElQhydpcbqH50hE8Vs2K6TkAeLhICYfndb67CVH0UsZaijmRUE3rHlIxU1u0jxwhgVe6fK3YANA==} dev: true /emittery@0.13.1: @@ -2562,39 +2620,51 @@ packages: is-arrayish: 0.2.1 dev: true - /esbuild@0.19.11: - resolution: {integrity: sha512-HJ96Hev2hX/6i5cDVwcqiJBBtuo9+FeIJOtZ9W1kA5M6AMJRHUZlpYZ1/SbEwtO0ioNAW8rUooVpC/WehY2SfA==} + /es-define-property@1.0.0: + resolution: {integrity: sha512-jxayLKShrEqqzJ0eumQbVhTYQM27CfT1T35+gCgDFoL82JLsXqTJ76zv6A0YLOgEnLUMvLzsDsGIrl8NFpT2gQ==} + engines: {node: '>= 0.4'} + dependencies: + get-intrinsic: 1.2.4 + dev: true + + /es-errors@1.3.0: + resolution: {integrity: sha512-Zf5H2Kxt2xjTvbJvP2ZWLEICxA6j+hAmMzIlypy4xcBg1vKVnx89Wy0GbS+kf5cwCVFFzdCFh2XSCFNULS6csw==} + engines: {node: '>= 0.4'} + dev: true + + /esbuild@0.19.12: + resolution: {integrity: sha512-aARqgq8roFBj054KvQr5f1sFu0D65G+miZRCuJyJ0G13Zwx7vRar5Zhn2tkQNzIXcBrNVsv/8stehpj+GAjgbg==} engines: {node: '>=12'} hasBin: true requiresBuild: true optionalDependencies: - '@esbuild/aix-ppc64': 0.19.11 - '@esbuild/android-arm': 0.19.11 - '@esbuild/android-arm64': 0.19.11 - '@esbuild/android-x64': 0.19.11 - '@esbuild/darwin-arm64': 0.19.11 - '@esbuild/darwin-x64': 0.19.11 - '@esbuild/freebsd-arm64': 0.19.11 - '@esbuild/freebsd-x64': 0.19.11 - '@esbuild/linux-arm': 0.19.11 - '@esbuild/linux-arm64': 0.19.11 - '@esbuild/linux-ia32': 0.19.11 - '@esbuild/linux-loong64': 0.19.11 - '@esbuild/linux-mips64el': 0.19.11 - '@esbuild/linux-ppc64': 0.19.11 - '@esbuild/linux-riscv64': 0.19.11 - '@esbuild/linux-s390x': 0.19.11 - '@esbuild/linux-x64': 0.19.11 - '@esbuild/netbsd-x64': 0.19.11 - '@esbuild/openbsd-x64': 0.19.11 - '@esbuild/sunos-x64': 0.19.11 - '@esbuild/win32-arm64': 0.19.11 - '@esbuild/win32-ia32': 0.19.11 - '@esbuild/win32-x64': 0.19.11 - dev: true - - /escalade@3.1.1: - resolution: {integrity: sha512-k0er2gUkLf8O0zKJiAhmkTnJlTvINGv7ygDNPbeIsX/TJjGJZHuh9B2UxbsaEkmlEo9MfhrSzmhIlhRlI2GXnw==} + '@esbuild/aix-ppc64': 0.19.12 + '@esbuild/android-arm': 0.19.12 + '@esbuild/android-arm64': 0.19.12 + '@esbuild/android-x64': 0.19.12 + '@esbuild/darwin-arm64': 0.19.12 + '@esbuild/darwin-x64': 0.19.12 + '@esbuild/freebsd-arm64': 0.19.12 + '@esbuild/freebsd-x64': 0.19.12 + '@esbuild/linux-arm': 0.19.12 + '@esbuild/linux-arm64': 0.19.12 + '@esbuild/linux-ia32': 0.19.12 + '@esbuild/linux-loong64': 0.19.12 + '@esbuild/linux-mips64el': 0.19.12 + '@esbuild/linux-ppc64': 0.19.12 + '@esbuild/linux-riscv64': 0.19.12 + '@esbuild/linux-s390x': 0.19.12 + '@esbuild/linux-x64': 0.19.12 + '@esbuild/netbsd-x64': 0.19.12 + '@esbuild/openbsd-x64': 0.19.12 + '@esbuild/sunos-x64': 0.19.12 + '@esbuild/win32-arm64': 0.19.12 + '@esbuild/win32-ia32': 0.19.12 + '@esbuild/win32-x64': 0.19.12 + dev: true + + /escalade@3.1.2: + resolution: {integrity: sha512-ErCHMCae19vR8vQGe50xIsVomy19rg6gFu3+r3jkEO46suLMWBksvVyoGgQV+jOfl84ZSOSlmv6Gxa89PmTGmA==} engines: {node: '>=6'} dev: true @@ -2643,15 +2713,15 @@ packages: engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} dev: true - /eslint@8.56.0: - resolution: {integrity: sha512-Go19xM6T9puCOWntie1/P997aXxFsOi37JIHRWI514Hc6ZnaHGKY9xFhrU65RT6CcBEzZoGG1e6Nq+DT04ZtZQ==} + /eslint@8.57.0: + resolution: {integrity: sha512-dZ6+mexnaTIbSBZWgou51U6OmzIhYM2VcNdtiTtI7qPNZm35Akpr0f6vtw3w1Kmn5PYo+tZVfh13WrhpS6oLqQ==} engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} hasBin: true dependencies: - '@eslint-community/eslint-utils': 4.4.0(eslint@8.56.0) + '@eslint-community/eslint-utils': 4.4.0(eslint@8.57.0) '@eslint-community/regexpp': 4.10.0 '@eslint/eslintrc': 2.1.4 - '@eslint/js': 8.56.0 + '@eslint/js': 8.57.0 '@humanwhocodes/config-array': 0.11.14 '@humanwhocodes/module-importer': 1.0.1 '@nodelib/fs.walk': 1.2.8 @@ -2673,7 +2743,7 @@ packages: glob-parent: 6.0.2 globals: 13.24.0 graphemer: 1.4.0 - ignore: 5.3.0 + ignore: 5.3.1 imurmurhash: 0.1.4 is-glob: 4.0.3 is-path-inside: 3.0.3 @@ -2753,7 +2823,7 @@ packages: human-signals: 5.0.0 is-stream: 3.0.0 merge-stream: 2.0.0 - npm-run-path: 5.2.0 + npm-run-path: 5.3.0 onetime: 6.0.0 signal-exit: 4.1.0 strip-final-newline: 3.0.0 @@ -2764,17 +2834,18 @@ packages: engines: {node: '>= 0.8.0'} dev: true - /expect-webdriverio@4.8.1(typescript@5.1.6): - resolution: {integrity: sha512-JD5aboj/tCiMXdEPCpt3BA0xL3DBhNu1MoiOdBGT9LT+9COIXoDG6Ks6h5S4c4PNwLs6xSeU8s7XxFAmBPu45Q==} + /expect-webdriverio@4.11.9(typescript@5.1.6): + resolution: {integrity: sha512-nHVLoC4W8wuVAyfpitJ07iDMLjeQ2OeYVjrKEb7dMeG4fqlegzN1SGYnnsKay+KWrte9KzuW1pZ7h5Nmbm/hAQ==} engines: {node: '>=16 || >=18 || >=20'} dependencies: + '@vitest/snapshot': 1.3.1 expect: 29.7.0 jest-matcher-utils: 29.7.0 lodash.isequal: 4.5.0 optionalDependencies: - '@wdio/globals': 8.27.2(typescript@5.1.6) - '@wdio/logger': 8.24.12 - webdriverio: 8.27.2(typescript@5.1.6) + '@wdio/globals': 8.32.3(typescript@5.1.6) + '@wdio/logger': 8.28.0 + webdriverio: 8.32.3(typescript@5.1.6) transitivePeerDependencies: - bufferutil - devtools @@ -2849,8 +2920,8 @@ packages: resolution: {integrity: sha512-DCXu6Ifhqcks7TZKY3Hxp3y6qphY5SJZmrWMDrKcERSOXWQdMhU9Ig/PYrzyw/ul9jOIyh0N4M0tbC5hodg8dw==} dev: true - /fastq@1.16.0: - resolution: {integrity: sha512-ifCoaXsDrsdkWTtiNJX5uzHDsrck5TzfKKDcuFFTIrrc/BS076qgEIfoIy1VeZqViznfKiysPYTh/QeHtnIsYA==} + /fastq@1.17.1: + resolution: {integrity: sha512-sRVD3lWVIXWg6By68ZN7vho9a1pQcN/WBFaAAsDDFzlJjvoGx0P8z7V1t72grFJfJhu3YPZBuu25f7Kaw2jN1w==} dependencies: reusify: 1.0.4 dev: true @@ -2872,7 +2943,7 @@ packages: engines: {node: ^12.20 || >= 14.13} dependencies: node-domexception: 1.0.0 - web-streams-polyfill: 3.3.2 + web-streams-polyfill: 3.3.3 dev: true /figures@5.0.0: @@ -2931,7 +3002,7 @@ packages: resolution: {integrity: sha512-CYcENa+FtcUKLmhhqyctpclsq7QF38pKjZHsGNiSQF5r4FtoKDWabFDl3hzaEQMvT1LHEysw5twgLvpYYb4vbw==} engines: {node: ^10.12.0 || >=12.0.0} dependencies: - flatted: 3.2.9 + flatted: 3.3.1 keyv: 4.5.4 rimraf: 3.0.2 dev: true @@ -2941,8 +3012,8 @@ packages: hasBin: true dev: true - /flatted@3.2.9: - resolution: {integrity: sha512-36yxDn5H7OFZQla0/jFJmbIKTdZAQHngCedGxiMmpNfEZM0sdEeT+WczLQrjK6D7o2aiyLYDnkw0R3JK0Qv1RQ==} + /flatted@3.3.1: + resolution: {integrity: sha512-X8cqMLLie7KsNUDSdzeN8FYK9rEt4Dt67OsG/DNGnYTSDBG4uFAJFBnUeiV+zCVAvwFy56IjM9sH51jVaEhNxw==} dev: true /foreground-child@3.1.1: @@ -2983,15 +3054,6 @@ packages: universalify: 2.0.1 dev: true - /fs-extra@8.1.0: - resolution: {integrity: sha512-yhlQgA6mnOJUKOsRUFsgJdQCvkKhcz8tlZG5HBQfReYZy46OwLcY+Zia0mtdHsOo9y/hP+CxMN0TU9QxoOtG4g==} - engines: {node: '>=6 <7 || >=8'} - dependencies: - graceful-fs: 4.2.11 - jsonfile: 4.0.0 - universalify: 0.1.2 - dev: true - /fs.realpath@1.0.0: resolution: {integrity: sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw==} dev: true @@ -3025,18 +3087,18 @@ packages: globule: 1.3.4 dev: true - /geckodriver@4.3.0: - resolution: {integrity: sha512-QfpvxFsMORwKpvnLslkHCr3NTCczHAvkte6+pQGsiUZXKBe6mO4TTb727b+9KMVSK6XZqhR6ZwImKdP+F5vS6A==} + /geckodriver@4.3.3: + resolution: {integrity: sha512-we2c2COgxFkLVuoknJNx+ioP+7VDq0sr6SCqWHTzlA4kzIbzR0EQ1Pps34s8WrsOnQqPC8a4sZV9dRPROOrkSg==} engines: {node: ^16.13 || >=18 || >=20} hasBin: true requiresBuild: true dependencies: - '@wdio/logger': 8.24.12 + '@wdio/logger': 8.28.0 decamelize: 6.0.0 - http-proxy-agent: 7.0.0 - https-proxy-agent: 7.0.2 + http-proxy-agent: 7.0.2 + https-proxy-agent: 7.0.4 node-fetch: 3.3.2 - tar-fs: 3.0.4 + tar-fs: 3.0.5 unzipper: 0.10.14 which: 4.0.0 transitivePeerDependencies: @@ -3057,13 +3119,15 @@ packages: resolution: {integrity: sha512-8vXOvuE167CtIc3OyItco7N/dpRtBbYOsPsXCz7X/PMnlGjYjSGuZJgM1Y7mmew7BKf9BqvLX2tnOVy1BBUsxQ==} dev: true - /get-intrinsic@1.2.2: - resolution: {integrity: sha512-0gSo4ml/0j98Y3lngkFEot/zhiCeWsbYIlZ+uZOVgzLyLaUw7wxUL+nCTP0XJvJg1AXulJRI3UJi8GsbDuxdGA==} + /get-intrinsic@1.2.4: + resolution: {integrity: sha512-5uYhsJH8VJBTv7oslg4BznJYhDoRI6waYCxMmCdnTrcCrHA/fCFKoTFz2JKKE0HdDFUF7/oQuhzumXJK7paBRQ==} + engines: {node: '>= 0.4'} dependencies: + es-errors: 1.3.0 function-bind: 1.1.2 - has-proto: 1.0.1 + has-proto: 1.0.3 has-symbols: 1.0.3 - hasown: 2.0.0 + hasown: 2.0.1 dev: true /get-package-type@0.1.0: @@ -3093,14 +3157,14 @@ packages: engines: {node: '>=16'} dev: true - /get-uri@6.0.2: - resolution: {integrity: sha512-5KLucCJobh8vBY1K07EFV4+cPZH3mrV9YeAruUseCQKHB58SGjjT2l9/eA9LD082IiuMjSlFJEcdJ27TXvbZNw==} + /get-uri@6.0.3: + resolution: {integrity: sha512-BzUrJBS9EcUb4cFol8r4W3v1cPsSyajLSthNkz5BxbpDcHN5tIrM10E2eNvfnvBn3DaT3DUgx0OpsBKkaOpanw==} engines: {node: '>= 14'} dependencies: - basic-ftp: 5.0.4 - data-uri-to-buffer: 6.0.1 + basic-ftp: 5.0.5 + data-uri-to-buffer: 6.0.2 debug: 4.3.4(supports-color@8.1.1) - fs-extra: 8.1.0 + fs-extra: 11.2.0 transitivePeerDependencies: - supports-color dev: true @@ -3142,17 +3206,6 @@ packages: path-is-absolute: 1.0.1 dev: true - /glob@7.2.0: - resolution: {integrity: sha512-lmLf6gtyrPq8tTjSmrO94wBeQbFR3HbLHbuyD69wuyQkImp2hWqMGB47OX65FBkPffO641IP9jWa1z4ivqG26Q==} - dependencies: - fs.realpath: 1.0.0 - inflight: 1.0.6 - inherits: 2.0.4 - minimatch: 3.1.2 - once: 1.4.0 - path-is-absolute: 1.0.1 - dev: true - /glob@7.2.3: resolution: {integrity: sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==} dependencies: @@ -3171,7 +3224,7 @@ packages: fs.realpath: 1.0.0 inflight: 1.0.6 inherits: 2.0.4 - minimatch: 5.1.6 + minimatch: 5.0.1 once: 1.4.0 dev: true @@ -3194,7 +3247,7 @@ packages: array-union: 2.1.0 dir-glob: 3.0.1 fast-glob: 3.3.2 - ignore: 5.3.0 + ignore: 5.3.1 merge2: 1.4.1 slash: 3.0.0 dev: true @@ -3211,7 +3264,7 @@ packages: /gopd@1.0.1: resolution: {integrity: sha512-d65bNlIadxvpb/A2abVdlqKqV563juRnZ1Wtk6s1sIR8uNsXR70xqIzVqxVf1eTqDunwT2MkczEeaezCKTZhwA==} dependencies: - get-intrinsic: 1.2.2 + get-intrinsic: 1.2.4 dev: true /got@12.6.1: @@ -3266,14 +3319,14 @@ packages: engines: {node: '>=8'} dev: true - /has-property-descriptors@1.0.1: - resolution: {integrity: sha512-VsX8eaIewvas0xnvinAe9bw4WfIeODpGYikiWYLH+dma0Jw6KHYqWiWfhQlgOVK8D6PvjubK5Uc4P0iIhIcNVg==} + /has-property-descriptors@1.0.2: + resolution: {integrity: sha512-55JNKuIW+vq4Ke1BjOTjM2YctQIvCT7GFzHwmfZPGo5wnrgkid0YQtnAleFSqumZm4az3n2BS+erby5ipJdgrg==} dependencies: - get-intrinsic: 1.2.2 + es-define-property: 1.0.0 dev: true - /has-proto@1.0.1: - resolution: {integrity: sha512-7qE+iP+O+bgF9clE5+UoBFzE65mlBiVj3tKCrlNQ0Ogwm0BjpT/gK4SlLYDMybDh5I3TCTKnPPa0oMG7JDYrhg==} + /has-proto@1.0.3: + resolution: {integrity: sha512-SJ1amZAJUiZS+PhsVLf5tGydlaVB8EdFpaSO4gmiUKUOxk8qzn5AIy4ZeJUmh22znIdk/uMAUT2pl3FxzVUH+Q==} engines: {node: '>= 0.4'} dev: true @@ -3282,8 +3335,8 @@ packages: engines: {node: '>= 0.4'} dev: true - /hasown@2.0.0: - resolution: {integrity: sha512-vUptKVTpIJhcczKBbgnS+RtcuYMB8+oNzPK2/Hp3hanz8JmpATdmmgLgSaadVREkDm+e2giHwY3ZRkyjSIDDFA==} + /hasown@2.0.1: + resolution: {integrity: sha512-1/th4MHjnwncwXsIW6QMzlvYL9kG5e/CpVvLRZe4XPa8TOUNbCELqmvhDmnkNsAjwaG4+I8gJJL0JBvTTLO9qA==} engines: {node: '>= 0.4'} dependencies: function-bind: 1.1.2 @@ -3298,7 +3351,7 @@ packages: resolution: {integrity: sha512-+K84LB1DYwMHoHSgaOY/Jfhw3ucPmSET5v98Ke/HdNSw4a0UktWzyW1mjhjpuxxTqOOsfWT/7iVshHmVZ4IpOA==} engines: {node: ^16.14.0 || >=18.0.0} dependencies: - lru-cache: 10.1.0 + lru-cache: 10.2.0 dev: true /html-encoding-sniffer@3.0.0: @@ -3327,8 +3380,8 @@ packages: - supports-color dev: true - /http-proxy-agent@7.0.0: - resolution: {integrity: sha512-+ZT+iBxVUQ1asugqnD6oWoRiS25AkjNfG085dKJGtGxkdwLQrMKU5wJr2bOOFAXzKcTuqq+7fZlTMgG3SRfIYQ==} + /http-proxy-agent@7.0.2: + resolution: {integrity: sha512-T1gkAiYYDWYx3V5Bmyu7HcfcvL7mUrTWiM6yOfa3PIphViJ/gFPbvidQ+veqSOHci/PxBcDabeUNCzpOODJZig==} engines: {node: '>= 14'} dependencies: agent-base: 7.1.0 @@ -3355,8 +3408,8 @@ packages: - supports-color dev: true - /https-proxy-agent@7.0.2: - resolution: {integrity: sha512-NmLNjm6ucYwtcUmL7JQC1ZQ57LmHP4lT15FQ8D61nak1rO6DH+fz5qNK2Ap5UN4ZapYICE3/0KodcLYSPsPbaA==} + /https-proxy-agent@7.0.4: + resolution: {integrity: sha512-wlwpilI7YdjSkWaQ/7omYBMTliDcmCN8OLihO6I9B86g06lMyAoqgoDpV0XqoaPOKj+0DIdAvnsWfyAAhmimcg==} engines: {node: '>= 14'} dependencies: agent-base: 7.1.0 @@ -3393,8 +3446,8 @@ packages: resolution: {integrity: sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA==} dev: true - /ignore@5.3.0: - resolution: {integrity: sha512-g7dmpshy+gD7mh88OC9NwSGTKoc3kyLAZQRU1mt53Aw/vnvfXnbC+F/7F7QoYVKbV+KNvJx8wArewKy1vXMtlg==} + /ignore@5.3.1: + resolution: {integrity: sha512-5Fytz/IraMjqpwfd34ke28PTVMjZjJG2MPn5t7OE4eUCUNf8BAa7b5WUS9/Qvr6mwOQS7Mk6vdsMno5he+T8Xw==} engines: {node: '>= 4'} dev: true @@ -3439,7 +3492,7 @@ packages: resolution: {integrity: sha512-mg3Fh9g2zfuVWJn6lhST0O7x4n03k7G8Tx5nvikJkbq8/CK47WDVm+UznF0G6s5Zi0KcyUisr6DU8T67N5U+1Q==} engines: {node: '>=14.18.0'} dependencies: - '@ljharb/through': 2.3.11 + '@ljharb/through': 2.3.12 ansi-escapes: 4.3.2 chalk: 5.3.0 cli-cursor: 3.1.0 @@ -3456,19 +3509,19 @@ packages: wrap-ansi: 6.2.0 dev: true + /ip-address@9.0.5: + resolution: {integrity: sha512-zHtQzGojZXTwZTHQqra+ETKd4Sn3vgi7uBmlPoXVWZqYvuKmtI0l/VZTjqGmJY9x88GGOaZ9+G9ES8hC4T4X8g==} + engines: {node: '>= 12'} + dependencies: + jsbn: 1.1.0 + sprintf-js: 1.1.3 + dev: true + /ip-regex@4.3.0: resolution: {integrity: sha512-B9ZWJxHHOHUhUjCPrMpLD4xEq35bUTClHM1S6CBU5ixQnkZmwipwgc96vAd7AAGM9TGHvJR+Uss+/Ak6UphK+Q==} engines: {node: '>=8'} dev: true - /ip@1.1.8: - resolution: {integrity: sha512-PuExPYUiu6qMBQb4l06ecm6T6ujzhmh+MeJcW9wa89PoAz5pvd4zPgN5WJV104mb6S2T1AwNIAaB70JNrLQWhg==} - dev: true - - /ip@2.0.0: - resolution: {integrity: sha512-WKa+XuLG1A1R0UWhl2+1XQSi+fZWMsYKffMZTTYsiZaUD8k2yDAj5atimTUD2TZkyCkNEeYE5NhFZmupOGtjYQ==} - dev: true - /is-arrayish@0.2.1: resolution: {integrity: sha512-zz06S8t0ozoDXMG+ube26zeCTNXcKIPJZJi8hBrF4idCLms4CG9QtK7qBl1boi5ODzFpjswb5JPmHCbMpjaYzg==} dev: true @@ -3483,7 +3536,7 @@ packages: /is-core-module@2.13.1: resolution: {integrity: sha512-hHrIjvZsftOsvKSn2TRYl63zvxsgE0K+0mYMoH6gD4omR5IWB2KynivBQczo3+wF1cCkjzvptnI9Q0sPU66ilw==} dependencies: - hasown: 2.0.0 + hasown: 2.0.1 dev: true /is-extglob@2.1.1: @@ -3592,8 +3645,8 @@ packages: resolution: {integrity: sha512-pzqtp31nLv/XFOzXGuvhCb8qhjmTVo5vjVk19XE4CRlSWz0KoeJ3bw9XsA7nOp9YBf4qHjwBxkDzKcME/J29Yg==} engines: {node: '>=8'} dependencies: - '@babel/core': 7.23.7 - '@babel/parser': 7.23.6 + '@babel/core': 7.24.0 + '@babel/parser': 7.24.0 '@istanbuljs/schema': 0.1.3 istanbul-lib-coverage: 3.2.2 semver: 6.3.1 @@ -3601,15 +3654,15 @@ packages: - supports-color dev: true - /istanbul-lib-instrument@6.0.1: - resolution: {integrity: sha512-EAMEJBsYuyyztxMxW3g7ugGPkrZsV57v0Hmv3mm1uQsmB+QnZuepg731CRaIgeUVSdmsTngOkSnauNF8p7FIhA==} + /istanbul-lib-instrument@6.0.2: + resolution: {integrity: sha512-1WUsZ9R1lA0HtBSohTkm39WTPlNKSJ5iFk7UwqXkBLoHQT+hfqPsfsTDVuZdKGaBwn7din9bS7SsnoAr943hvw==} engines: {node: '>=10'} dependencies: - '@babel/core': 7.23.7 - '@babel/parser': 7.23.6 + '@babel/core': 7.24.0 + '@babel/parser': 7.24.0 '@istanbuljs/schema': 0.1.3 istanbul-lib-coverage: 3.2.2 - semver: 7.5.4 + semver: 7.6.0 transitivePeerDependencies: - supports-color dev: true @@ -3634,8 +3687,8 @@ packages: - supports-color dev: true - /istanbul-reports@3.1.6: - resolution: {integrity: sha512-TLgnMkKg3iTDsQ9PbPTdpfAK2DzjF9mqUG7RMgcQl8oFjad8ob4laGxv5XV5U9MAfx8D6tSJiUyuAwzLicaxlg==} + /istanbul-reports@3.1.7: + resolution: {integrity: sha512-BewmUXImeuRk2YY0PVbxgKAysvhRPUQE0h5QRM++nVWyubKGV0l8qQ5op8+B2DOmwSe63Jivj0BjkPQVf8fP5g==} engines: {node: '>=8'} dependencies: html-escaper: 2.0.2 @@ -3679,7 +3732,7 @@ packages: '@jest/expect': 29.7.0 '@jest/test-result': 29.7.0 '@jest/types': 29.6.3 - '@types/node': 20.11.2 + '@types/node': 20.11.24 chalk: 4.1.2 co: 4.6.0 dedent: 1.5.1 @@ -3700,7 +3753,7 @@ packages: - supports-color dev: true - /jest-cli@29.7.0(@types/node@20.11.2): + /jest-cli@29.7.0(@types/node@20.11.24): resolution: {integrity: sha512-OVVobw2IubN/GSYsxETi+gOe7Ka59EFMR/twOU3Jb2GnKKeMGJB5SGUUrEz3SFVmJASUdZUzy83sLNNQ2gZslg==} engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} hasBin: true @@ -3714,10 +3767,10 @@ packages: '@jest/test-result': 29.7.0 '@jest/types': 29.6.3 chalk: 4.1.2 - create-jest: 29.7.0(@types/node@20.11.2) + create-jest: 29.7.0(@types/node@20.11.24) exit: 0.1.2 import-local: 3.1.0 - jest-config: 29.7.0(@types/node@20.11.2) + jest-config: 29.7.0(@types/node@20.11.24) jest-util: 29.7.0 jest-validate: 29.7.0 yargs: 17.7.2 @@ -3728,7 +3781,7 @@ packages: - ts-node dev: true - /jest-config@29.7.0(@types/node@20.11.2): + /jest-config@29.7.0(@types/node@20.11.24): resolution: {integrity: sha512-uXbpfeQ7R6TZBqI3/TxCU4q4ttk3u0PJeC+E0zbfSoSjq6bJ7buBPxzQPL0ifrkY4DNu4JUdk0ImlBUYi840eQ==} engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} peerDependencies: @@ -3740,11 +3793,11 @@ packages: ts-node: optional: true dependencies: - '@babel/core': 7.23.7 + '@babel/core': 7.24.0 '@jest/test-sequencer': 29.7.0 '@jest/types': 29.6.3 - '@types/node': 20.11.2 - babel-jest: 29.7.0(@babel/core@7.23.7) + '@types/node': 20.11.24 + babel-jest: 29.7.0(@babel/core@7.24.0) chalk: 4.1.2 ci-info: 3.9.0 deepmerge: 4.3.1 @@ -3809,7 +3862,7 @@ packages: '@jest/fake-timers': 29.7.0 '@jest/types': 29.6.3 '@types/jsdom': 20.0.1 - '@types/node': 20.11.2 + '@types/node': 20.11.24 jest-mock: 29.7.0 jest-util: 29.7.0 jsdom: 20.0.3 @@ -3826,7 +3879,7 @@ packages: '@jest/environment': 29.7.0 '@jest/fake-timers': 29.7.0 '@jest/types': 29.6.3 - '@types/node': 20.11.2 + '@types/node': 20.11.24 jest-mock: 29.7.0 jest-util: 29.7.0 dev: true @@ -3846,7 +3899,7 @@ packages: dependencies: '@jest/types': 29.6.3 '@types/graceful-fs': 4.1.9 - '@types/node': 20.11.2 + '@types/node': 20.11.24 anymatch: 3.1.3 fb-watchman: 2.0.2 graceful-fs: 4.2.11 @@ -3897,7 +3950,7 @@ packages: engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} dependencies: '@jest/types': 29.6.3 - '@types/node': 20.11.2 + '@types/node': 20.11.24 jest-util: 29.7.0 dev: true @@ -3952,7 +4005,7 @@ packages: '@jest/test-result': 29.7.0 '@jest/transform': 29.7.0 '@jest/types': 29.6.3 - '@types/node': 20.11.2 + '@types/node': 20.11.24 chalk: 4.1.2 emittery: 0.13.1 graceful-fs: 4.2.11 @@ -3983,7 +4036,7 @@ packages: '@jest/test-result': 29.7.0 '@jest/transform': 29.7.0 '@jest/types': 29.6.3 - '@types/node': 20.11.2 + '@types/node': 20.11.24 chalk: 4.1.2 cjs-module-lexer: 1.2.3 collect-v8-coverage: 1.0.2 @@ -4006,15 +4059,15 @@ packages: resolution: {integrity: sha512-Rm0BMWtxBcioHr1/OX5YCP8Uov4riHvKPknOGs804Zg9JGZgmIBkbtlxJC/7Z4msKYVbIJtfU+tKb8xlYNfdkw==} engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} dependencies: - '@babel/core': 7.23.7 + '@babel/core': 7.24.0 '@babel/generator': 7.23.6 - '@babel/plugin-syntax-jsx': 7.23.3(@babel/core@7.23.7) - '@babel/plugin-syntax-typescript': 7.23.3(@babel/core@7.23.7) - '@babel/types': 7.23.6 + '@babel/plugin-syntax-jsx': 7.23.3(@babel/core@7.24.0) + '@babel/plugin-syntax-typescript': 7.23.3(@babel/core@7.24.0) + '@babel/types': 7.24.0 '@jest/expect-utils': 29.7.0 '@jest/transform': 29.7.0 '@jest/types': 29.6.3 - babel-preset-current-node-syntax: 1.0.1(@babel/core@7.23.7) + babel-preset-current-node-syntax: 1.0.1(@babel/core@7.24.0) chalk: 4.1.2 expect: 29.7.0 graceful-fs: 4.2.11 @@ -4025,7 +4078,7 @@ packages: jest-util: 29.7.0 natural-compare: 1.4.0 pretty-format: 29.7.0 - semver: 7.5.4 + semver: 7.6.0 transitivePeerDependencies: - supports-color dev: true @@ -4035,7 +4088,7 @@ packages: engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} dependencies: '@jest/types': 29.6.3 - '@types/node': 20.11.2 + '@types/node': 20.11.24 chalk: 4.1.2 ci-info: 3.9.0 graceful-fs: 4.2.11 @@ -4060,7 +4113,7 @@ packages: dependencies: '@jest/test-result': 29.7.0 '@jest/types': 29.6.3 - '@types/node': 20.11.2 + '@types/node': 20.11.24 ansi-escapes: 4.3.2 chalk: 4.1.2 emittery: 0.13.1 @@ -4072,13 +4125,13 @@ packages: resolution: {integrity: sha512-eIz2msL/EzL9UFTFFx7jBTkeZfku0yUAyZZZmJ93H2TYEiroIx2PQjEXcwYtYl8zXCxb+PAmA2hLIt/6ZEkPHw==} engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} dependencies: - '@types/node': 20.11.2 + '@types/node': 20.11.24 jest-util: 29.7.0 merge-stream: 2.0.0 supports-color: 8.1.1 dev: true - /jest@29.7.0(@types/node@20.11.2): + /jest@29.7.0(@types/node@20.11.24): resolution: {integrity: sha512-NIy3oAFp9shda19hy4HK0HRTWKtPJmGdnvywu01nOqNC2vZg+Z+fvJDxpMQA88eb2I9EcafcdjYgsDthnYTvGw==} engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} hasBin: true @@ -4091,7 +4144,7 @@ packages: '@jest/core': 29.7.0 '@jest/types': 29.6.3 import-local: 3.1.0 - jest-cli: 29.7.0(@types/node@20.11.2) + jest-cli: 29.7.0(@types/node@20.11.24) transitivePeerDependencies: - '@types/node' - babel-plugin-macros @@ -4118,6 +4171,10 @@ packages: argparse: 2.0.1 dev: true + /jsbn@1.1.0: + resolution: {integrity: sha512-4bYVV3aAMtDTTu4+xsDYa6sy9GyJ69/amsu9sYF2zqjiEoZA5xJi3BrfX3uY+/IekIu7MwdObdbDWpoZdBv3/A==} + dev: true + /jsdom@20.0.3: resolution: {integrity: sha512-SYhBvTh89tTfCD/CRdSOm13mOBa42iTaTyfyEWBdKcGdPxPtLFBXuHR8XHb33YNYaP+lLbmSvBTsnoesCNJEsQ==} engines: {node: '>=14'} @@ -4192,12 +4249,6 @@ packages: hasBin: true dev: true - /jsonfile@4.0.0: - resolution: {integrity: sha512-m6F1R3z8jjlf2imQHS2Qez5sjKWQzbuuhuJ/FKYFRZvPE3PuHcSMVZzfsLhGVOkfd20obL5SWEBew5ShlquNxg==} - optionalDependencies: - graceful-fs: 4.2.11 - dev: true - /jsonfile@6.1.0: resolution: {integrity: sha512-5dgndWOriYSm5cnYaJNhalLNDKOqFwyDB/rr1E9ZsGciGvKPs8R2xYGCacuf3z6K1YKDz182fd+fY3cn3pMqXQ==} dependencies: @@ -4255,10 +4306,10 @@ packages: resolution: {integrity: sha512-3mk/Zag0+IJxeDrxSgaDPy4zZ3w05PRZeJNnlWhzFz5OkX49J4krc+A8X2d2M69vGMBEX0uyl8M+W+8gH+kBqQ==} dev: true - /locate-app@2.2.7: - resolution: {integrity: sha512-4NR8WidaCRCozDZ0BW0U5wL91EPuuIshFun2//4Kpca4DIi5XPQHAUEbj+MQt7NihZTYs+HKfOuaoqurZ58bUg==} + /locate-app@2.2.20: + resolution: {integrity: sha512-TOCp8H9l75GhNtd+BgyUnLMNzR+IpYge7cWjxELsyDlqH+MyYWxq+NfyjQ+o6oRAORzOs3IfMM6KAR6q3JNfhg==} dependencies: - n12: 1.8.10 + n12: 1.8.23 type-fest: 2.13.0 userhome: 1.0.0 dev: true @@ -4333,8 +4384,8 @@ packages: resolution: {integrity: sha512-WpG9CcFAOjz/FtNht+QJeGpvVl/cdR6P0z6OcXSkr8wFJOsV2GRj2j10JLfjuA4aYkcKCNIEqRGCyTife9R8/g==} dev: true - /loglevel@1.8.1: - resolution: {integrity: sha512-tCRIJM51SHjAayKwC+QAg8hT8vg6z7GSgLJKGvzuPb1Wc+hLzqtuVLxp6/HzSPOozuK+8ErAhy7U/sVzw8Dgfg==} + /loglevel@1.9.1: + resolution: {integrity: sha512-hP3I3kCrDIMuRwAwHltphhDM1r8i55H33GgqjXbrisuJhF4kRhW1dNuxsRklp4bXl8DSdLaNLuiL4A/LWRfxvg==} engines: {node: '>= 0.6.0'} dev: true @@ -4349,8 +4400,8 @@ packages: engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0} dev: true - /lru-cache@10.1.0: - resolution: {integrity: sha512-/1clY/ui8CzjKFyjdvwPWJUYKiFVXG2I2cY0ssG7h4+hwk+XOIX7ZSG9Q7TW8TW3Kp3BUSqgFWBLgL4PJ+Blag==} + /lru-cache@10.2.0: + resolution: {integrity: sha512-2bIM8x+VAf6JT4bKAljS1qUWgMsqZRPGJS6FSahIMPVvctcNhyVp7AJu7quxOW9jwkryBReKZY5tY5JYv2n/7Q==} engines: {node: 14 || >=16.14} dev: true @@ -4372,11 +4423,18 @@ packages: engines: {node: '>=12'} dev: true + /magic-string@0.30.7: + resolution: {integrity: sha512-8vBuFF/I/+OSLRmdf2wwFCJCz+nSn0m6DPvGH1fS/KiQoSaR+sETbov0eIk9KhEKy8CYqIkIAnbohxT/4H0kuA==} + engines: {node: '>=12'} + dependencies: + '@jridgewell/sourcemap-codec': 1.4.15 + dev: true + /make-dir@4.0.0: resolution: {integrity: sha512-hXdUTZYIVOt1Ex//jAQi+wTZZpUpwBj/0QsOzqegb3rGMMeJiSEu5xLHnYfBrRV4RH2+OCSOO95Is/7x1WJ4bw==} engines: {node: '>=10'} dependencies: - semver: 7.5.4 + semver: 7.6.0 dev: true /make-error@1.3.6: @@ -4495,8 +4553,8 @@ packages: minimist: 1.2.8 dev: true - /mocha@10.2.0: - resolution: {integrity: sha512-IDY7fl/BecMwFHzoqF2sg/SHHANeBoMMXFlS9r0OXKDssYE1M5O43wUY/9BVPeIvfH2zmEbBfseqN9gBQZzXkg==} + /mocha@10.3.0: + resolution: {integrity: sha512-uF2XJs+7xSLsrmIvn37i/wnc91nw7XjOQB8ccyx5aEgdnohr7n+rEiZP23WkCYHjilR6+EboEnbq/ZQDz4LSbg==} engines: {node: '>= 14.0.0'} hasBin: true dependencies: @@ -4507,13 +4565,12 @@ packages: diff: 5.0.0 escape-string-regexp: 4.0.0 find-up: 5.0.0 - glob: 7.2.0 + glob: 8.1.0 he: 1.2.0 js-yaml: 4.1.0 log-symbols: 4.1.0 minimatch: 5.0.1 ms: 2.1.3 - nanoid: 3.3.3 serialize-javascript: 6.0.0 strip-json-comments: 3.1.1 supports-color: 8.1.1 @@ -4544,14 +4601,8 @@ packages: engines: {node: ^14.17.0 || ^16.13.0 || >=18.0.0} dev: true - /n12@1.8.10: - resolution: {integrity: sha512-/iREutgBDWCLwSqVOTKyAXRfToeY8Y9PmFPk3egwWVf6UYUyL9UXIaVnEkW4mx+g3dBGBywfvWilfKFEkiGK+A==} - dev: true - - /nanoid@3.3.3: - resolution: {integrity: sha512-p1sjXuopFs0xg+fPASzQ28agW1oHD7xDsd9Xkf3T15H3c/cifrFHVwrh74PdoklAPi+i7MdRsE47vm2r6JoB+w==} - engines: {node: ^10 || ^12 || ^13.7 || ^14 || >=15.0.1} - hasBin: true + /n12@1.8.23: + resolution: {integrity: sha512-kQITb5LlO0Gk8rmbMAkfbmhs+QlXZ5SRHsx6YcG++3yc57iolbiQuo5rsfu3dkB7Qw3jKCqntsZvNNgvdfotkA==} dev: true /natural-compare@1.4.0: @@ -4607,7 +4658,7 @@ packages: dependencies: hosted-git-info: 7.0.1 is-core-module: 2.13.1 - semver: 7.5.4 + semver: 7.6.0 validate-npm-package-license: 3.0.4 dev: true @@ -4628,8 +4679,8 @@ packages: path-key: 3.1.1 dev: true - /npm-run-path@5.2.0: - resolution: {integrity: sha512-W4/tgAXFqFA0iL7fk0+uQ3g7wkL8xJmx3XdK0VGb4cHW//eZTtKGvFBBoRKVTpY7n6ze4NL9ly7rgXcHufqXKg==} + /npm-run-path@5.3.0: + resolution: {integrity: sha512-ppwTtiJZq0O/ai0z7yfudtBpWIoxM8yE6nHi1X47eFR2EWORqfbu6CnPlNsjeN683eT0qG6H/Pyf9fCcvjnnnQ==} engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0} dependencies: path-key: 4.0.0 @@ -4643,14 +4694,14 @@ packages: resolution: {integrity: sha512-5qoj1RUiKOMsCCNLV1CBiPYE10sziTsnmNxkAI/rZhiD63CF7IqdFGC/XzjWjpSgLf0LxXX3bDFIh0E18f6UhQ==} dev: true - /obsidian@1.4.11(@codemirror/state@6.4.0)(@codemirror/view@6.23.0): - resolution: {integrity: sha512-BCVYTvaXxElJMl6MMbDdY/CGK+aq18SdtDY/7vH8v6BxCBQ6KF4kKxL0vG9UZ0o5qh139KpUoJHNm+6O5dllKA==} + /obsidian@1.5.7(@codemirror/state@6.4.1)(@codemirror/view@6.24.1): + resolution: {integrity: sha512-DNcvQJ6TvMflHZqWfO9cLGbOUbKTy2KBi6B6vjo5RG8XsftKZZq1zS/OQFhII2BnXK/DWan/lUcb2JYxfM3p5A==} peerDependencies: '@codemirror/state': ^6.0.0 '@codemirror/view': ^6.0.0 dependencies: - '@codemirror/state': 6.4.0 - '@codemirror/view': 6.23.0 + '@codemirror/state': 6.4.1 + '@codemirror/view': 6.24.1 '@types/codemirror': 5.60.8 moment: 2.29.4 dev: true @@ -4766,21 +4817,20 @@ packages: '@tootallnate/quickjs-emscripten': 0.23.0 agent-base: 7.1.0 debug: 4.3.4(supports-color@8.1.1) - get-uri: 6.0.2 - http-proxy-agent: 7.0.0 - https-proxy-agent: 7.0.2 - pac-resolver: 7.0.0 + get-uri: 6.0.3 + http-proxy-agent: 7.0.2 + https-proxy-agent: 7.0.4 + pac-resolver: 7.0.1 socks-proxy-agent: 8.0.2 transitivePeerDependencies: - supports-color dev: true - /pac-resolver@7.0.0: - resolution: {integrity: sha512-Fd9lT9vJbHYRACT8OhCbZBbxr6KRSawSovFpy8nDGshaK99S/EBhVIHp9+crhxrsZOuvLpgL1n23iyPg6Rl2hg==} + /pac-resolver@7.0.1: + resolution: {integrity: sha512-5NPgf87AT2STgwa2ntRMr45jTKrYBGkVU36yT0ig/n/GMAa3oPqhZfIQ2kMEimReg0+t9kZViDVZ83qfVUlckg==} engines: {node: '>= 14'} dependencies: degenerator: 5.0.1 - ip: 1.1.8 netmask: 2.0.2 dev: true @@ -4866,7 +4916,7 @@ packages: resolution: {integrity: sha512-MkhCqzzBEpPvxxQ71Md0b1Kk51W01lrYvlMzSUaIzNsODdd7mqhiimSZlr+VegAz5Z6Vzt9Xg2ttE//XBhH3EQ==} engines: {node: '>=16 || 14 >=14.17'} dependencies: - lru-cache: 10.1.0 + lru-cache: 10.2.0 minipass: 7.0.4 dev: true @@ -4875,6 +4925,10 @@ packages: engines: {node: '>=8'} dev: true + /pathe@1.1.2: + resolution: {integrity: sha512-whLdWMYL2TwI08hn8/ZqAbrVemu0LNaNNJZX73O6qaIdCTfXutsLhMkjdENX0qhsQ9uIimo4/aQOmXkoon2nDQ==} + dev: true + /pathval@1.1.1: resolution: {integrity: sha512-Dp6zGqpTdETdR63lehJYPeIOqpiNBNtc7BpWSLrOje7UaIsE5aY92r/AunQA7rsXvet3lrJ3JnZX29UPTKXyKQ==} dev: true @@ -4909,8 +4963,8 @@ packages: engines: {node: '>= 0.8.0'} dev: true - /prettier@3.2.2: - resolution: {integrity: sha512-HTByuKZzw7utPiDO523Tt2pLtEyK7OibUD9suEJQrPUCYQqrHr74GGX6VidMrovbf/I50mPqr8j/II6oBAuc5A==} + /prettier@3.2.5: + resolution: {integrity: sha512-3/GWa9aOC0YeD7LUfvOG2NiDyhOWRvt1k+rcKhOuYnMY24iiCphgneUfJDyFXd6rZCAnuLBv6UeAULtrhT/F4A==} engines: {node: '>=14'} hasBin: true dev: true @@ -4954,8 +5008,8 @@ packages: dependencies: agent-base: 7.1.0 debug: 4.3.4(supports-color@8.1.1) - http-proxy-agent: 7.0.0 - https-proxy-agent: 7.0.2 + http-proxy-agent: 7.0.2 + https-proxy-agent: 7.0.4 lru-cache: 7.18.3 pac-proxy-agent: 7.0.1 proxy-from-env: 1.1.0 @@ -4970,8 +5024,8 @@ packages: dependencies: agent-base: 7.1.0 debug: 4.3.4(supports-color@8.1.1) - http-proxy-agent: 7.0.0 - https-proxy-agent: 7.0.2 + http-proxy-agent: 7.0.2 + https-proxy-agent: 7.0.4 lru-cache: 7.18.3 pac-proxy-agent: 7.0.1 proxy-from-env: 1.1.0 @@ -5058,13 +5112,13 @@ packages: resolution: {integrity: sha512-xWGDIW6x921xtzPkhiULtthJHoJvBbF3q26fzloPCK0hsvxtPVelvftw3zjbHWSkR2km9Z+4uxbDDK/6Zw9B8w==} dev: true - /read-pkg-up@10.1.0: - resolution: {integrity: sha512-aNtBq4jR8NawpKJQldrQcSW9y/d+KWH4v24HWkHljOZ7H0av+YTGANBzRh9A5pw7v/bLVsLVPpOhJ7gHNVy8lA==} + /read-pkg-up@10.0.0: + resolution: {integrity: sha512-jgmKiS//w2Zs+YbX039CorlkOp8FIVbSAN8r8GJHDsGlmNPXo+VeHkqAwCiQVTTx5/LwLZTcEw59z3DvcLbr0g==} engines: {node: '>=16'} dependencies: find-up: 6.3.0 read-pkg: 8.1.0 - type-fest: 4.9.0 + type-fest: 3.13.1 dev: true /read-pkg@8.1.0: @@ -5074,7 +5128,7 @@ packages: '@types/normalize-package-data': 2.4.4 normalize-package-data: 6.0.0 parse-json: 7.1.1 - type-fest: 4.9.0 + type-fest: 4.10.3 dev: true /readable-stream@2.3.8: @@ -5251,8 +5305,8 @@ packages: hasBin: true dev: true - /semver@7.5.4: - resolution: {integrity: sha512-1bCSESV6Pv+i21Hvpxp3Dx+pSD8lIPt8uVjRrxAUt/nbswYc+tK6Y2btiULjd4+fnq15PX+nqQDC7Oft7WkwcA==} + /semver@7.6.0: + resolution: {integrity: sha512-EnwXhrlwXMk9gKu5/flx5sv/an57AkRplG3hTK68W7FRDN+k+OWBj65M7719OkA82XLBxrcX0KSHj+X5COhOVg==} engines: {node: '>=10'} hasBin: true dependencies: @@ -5272,15 +5326,16 @@ packages: randombytes: 2.1.0 dev: true - /set-function-length@1.2.0: - resolution: {integrity: sha512-4DBHDoyHlM1IRPGYcoxexgh67y4ueR53FKV1yyxwFMY7aCqcN/38M1+SwZ/qJQ8iLv7+ck385ot4CcisOAPT9w==} + /set-function-length@1.2.1: + resolution: {integrity: sha512-j4t6ccc+VsKwYHso+kElc5neZpjtq9EnRICFZtWyBsLojhmeF/ZBd/elqm22WJh/BziDe/SBiOeAt0m2mfLD0g==} engines: {node: '>= 0.4'} dependencies: - define-data-property: 1.1.1 + define-data-property: 1.1.4 + es-errors: 1.3.0 function-bind: 1.1.2 - get-intrinsic: 1.2.2 + get-intrinsic: 1.2.4 gopd: 1.0.1 - has-property-descriptors: 1.0.1 + has-property-descriptors: 1.0.2 dev: true /setimmediate@1.0.5: @@ -5328,16 +5383,16 @@ packages: dependencies: agent-base: 7.1.0 debug: 4.3.4(supports-color@8.1.1) - socks: 2.7.1 + socks: 2.8.1 transitivePeerDependencies: - supports-color dev: true - /socks@2.7.1: - resolution: {integrity: sha512-7maUZy1N7uo6+WVEX6psASxtNlKaNVMlGQKkG/63nEDdLOWNbiUMoLK7X4uYoLhQstau72mLgfEWcXcwsaHbYQ==} - engines: {node: '>= 10.13.0', npm: '>= 3.0.0'} + /socks@2.8.1: + resolution: {integrity: sha512-B6w7tkwNid7ToxjZ08rQMT8M9BJAf8DKx8Ft4NivzH0zBUfd6jldGcisJn/RLgxcX3FPNDdNQCUEMMT79b+oCQ==} + engines: {node: '>= 10.0.0', npm: '>= 3.0.0'} dependencies: - ip: 2.0.0 + ip-address: 9.0.5 smart-buffer: 4.2.0 dev: true @@ -5357,22 +5412,22 @@ packages: resolution: {integrity: sha512-kN9dJbvnySHULIluDHy32WHRUu3Og7B9sbY7tsFLctQkIqnMh3hErYgdMjTYuqmcXX+lK5T1lnUt3G7zNswmZA==} dependencies: spdx-expression-parse: 3.0.1 - spdx-license-ids: 3.0.16 + spdx-license-ids: 3.0.17 dev: true - /spdx-exceptions@2.3.0: - resolution: {integrity: sha512-/tTrYOC7PPI1nUAgx34hUpqXuyJG+DTHJTnIULG4rDygi4xu/tfgmq1e1cIRwRzwZgo4NLySi+ricLkZkw4i5A==} + /spdx-exceptions@2.5.0: + resolution: {integrity: sha512-PiU42r+xO4UbUS1buo3LPJkjlO7430Xn5SVAhdpzzsPHsjbYVflnnFdATgabnLude+Cqu25p6N+g2lw/PFsa4w==} dev: true /spdx-expression-parse@3.0.1: resolution: {integrity: sha512-cbqHunsQWnJNE6KhVSMsMeH5H/L9EpymbzqTQ3uLwNCLZ1Q481oWaofqH7nO6V07xlXwY6PhQdQ2IedWx/ZK4Q==} dependencies: - spdx-exceptions: 2.3.0 - spdx-license-ids: 3.0.16 + spdx-exceptions: 2.5.0 + spdx-license-ids: 3.0.17 dev: true - /spdx-license-ids@3.0.16: - resolution: {integrity: sha512-eWN+LnM3GR6gPu35WxNgbGl8rmY1AEmoMDvL/QD6zYmPWgywxWqJWNdLGT+ke8dKNWrcYgYjPpG5gbTfghP8rw==} + /spdx-license-ids@3.0.17: + resolution: {integrity: sha512-sh8PWc/ftMqAAdFiBu6Fy6JUOYjqDJBJvIhpfDMyHrr0Rbp5liZqd4TjtQ/RgfLjKFZb+LMx5hpml5qOWy0qvg==} dev: true /split2@4.2.0: @@ -5384,6 +5439,10 @@ packages: resolution: {integrity: sha512-D9cPgkvLlV3t3IzL0D0YLvGA9Ahk4PcvVwUbN0dSGr1aP0Nrt4AEnTUbuGvquEC0mA64Gqt1fzirlRs5ibXx8g==} dev: true + /sprintf-js@1.1.3: + resolution: {integrity: sha512-Oo+0REFV59/rz3gfJNKQiBlwfHaSESl1pcGyABQsnnIfWOFt6JNj5gCog2U6MLZ//IGYD+nA8nI+mTShREReaA==} + dev: true + /stack-utils@2.0.6: resolution: {integrity: sha512-XlkWvfIm6RmsWtNJx+uqtKLS8eqFbxUg0ZzLXqY0caEy9l7hruX8IpiDnjsLavoBgqCCR71TqWO8MaXYheJ3RQ==} engines: {node: '>=10'} @@ -5396,11 +5455,13 @@ packages: engines: {node: '>= 0.10.0'} dev: true - /streamx@2.15.6: - resolution: {integrity: sha512-q+vQL4AAz+FdfT137VF69Cc/APqUbxy+MDOImRrMvchJpigHj9GksgDU2LYbO9rx7RX6osWgxJB2WxhYv4SZAw==} + /streamx@2.16.1: + resolution: {integrity: sha512-m9QYj6WygWyWa3H1YY69amr4nVgy61xfjys7xO7kviL5rfIEc2naf+ewFiOA+aEJD7y0JO3h2GoiUv4TDwEGzQ==} dependencies: fast-fifo: 1.3.2 queue-tick: 1.0.1 + optionalDependencies: + bare-events: 2.2.1 dev: true /string-length@4.0.2: @@ -5475,8 +5536,8 @@ packages: engines: {node: '>=8'} dev: true - /style-mod@4.1.0: - resolution: {integrity: sha512-Ca5ib8HrFn+f+0n4N4ScTIA9iTOQ7MaGS1ylHcoVqW9J7w2w8PzN6g9gKmTYgGEBH8e120+RCmhpje6jC5uGWA==} + /style-mod@4.1.2: + resolution: {integrity: sha512-wnD1HyVqpJUI2+eKZ+eo1UwghftP6yuFheBqqe+bWCotBjC2K1YnteJILRMs3SM4V/0dLEW1SC27MWP5y+mwmw==} dev: true /supports-color@5.5.0: @@ -5514,15 +5575,25 @@ packages: dependencies: mkdirp-classic: 0.5.3 pump: 3.0.0 - tar-stream: 3.1.6 + tar-stream: 3.1.7 + dev: true + + /tar-fs@3.0.5: + resolution: {integrity: sha512-JOgGAmZyMgbqpLwct7ZV8VzkEB6pxXFBVErLtb+XCOqzc6w1xiWKI9GVd6bwk68EX7eJ4DWmfXVmq8K2ziZTGg==} + dependencies: + pump: 3.0.0 + tar-stream: 3.1.7 + optionalDependencies: + bare-fs: 2.2.1 + bare-path: 2.1.0 dev: true - /tar-stream@3.1.6: - resolution: {integrity: sha512-B/UyjYwPpMBv+PaFSWAmtYjwdrlEaZQEhMIBFNC5oEG8lpiW8XjcSdmEaClj28ArfKScKHs2nshz3k2le6crsg==} + /tar-stream@3.1.7: + resolution: {integrity: sha512-qJj60CXt7IU1Ffyc3NJMjh6EkuCFej46zUqJ4J7pqYlThyd9bO0XBTmcOIhSzZJVWfsLks0+nle/j538YAW9RQ==} dependencies: - b4a: 1.6.4 + b4a: 1.6.6 fast-fifo: 1.3.2 - streamx: 2.15.6 + streamx: 2.16.1 dev: true /tcp-port-used@1.0.2: @@ -5599,18 +5670,18 @@ packages: resolution: {integrity: sha512-iawgk0hLP3SxGKDfnDJf8wTz4p2qImnyihM5Hh/sGvQ3K37dPi/w8sRhdNIxYA1TwFwc5mDhIJq+O0RsvXBKdQ==} dev: true - /ts-api-utils@1.0.3(typescript@5.1.6): - resolution: {integrity: sha512-wNMeqtMz5NtwpT/UZGY5alT+VoKdSsOOP/kqHFcUW1P/VRhH2wJ48+DN2WwUliNbQ976ETwDL0Ifd2VVvgonvg==} - engines: {node: '>=16.13.0'} + /ts-api-utils@1.2.1(typescript@5.1.6): + resolution: {integrity: sha512-RIYA36cJn2WiH9Hy77hdF9r7oEwxAtB/TS9/S4Qd90Ap4z5FSiin5zEiTL44OII1Y3IIlEvxwxFUVgrHSZ/UpA==} + engines: {node: '>=16'} peerDependencies: typescript: '>=4.2.0' dependencies: typescript: 5.1.6 dev: true - /ts-jest@29.1.1(@babel/core@7.23.7)(esbuild@0.19.11)(jest@29.7.0)(typescript@5.1.6): - resolution: {integrity: sha512-D6xjnnbP17cC85nliwGiL+tpoKN0StpgE0TeOjXQTU6MVCfsB4v7aW05CgQ/1OywGb0x/oy9hHFnN+sczTiRaA==} - engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} + /ts-jest@29.1.2(@babel/core@7.24.0)(esbuild@0.19.12)(jest@29.7.0)(typescript@5.1.6): + resolution: {integrity: sha512-br6GJoH/WUX4pu7FbZXuWGKGNDuU7b8Uj77g/Sp7puZV6EXzuByl6JrECvm0MzVzSTkSHWTihsXt+5XYER5b+g==} + engines: {node: ^16.10.0 || ^18.0.0 || >=20.0.0} hasBin: true peerDependencies: '@babel/core': '>=7.0.0-beta.0 <8' @@ -5629,16 +5700,16 @@ packages: esbuild: optional: true dependencies: - '@babel/core': 7.23.7 + '@babel/core': 7.24.0 bs-logger: 0.2.6 - esbuild: 0.19.11 + esbuild: 0.19.12 fast-json-stable-stringify: 2.1.0 - jest: 29.7.0(@types/node@20.11.2) + jest: 29.7.0(@types/node@20.11.24) jest-util: 29.7.0 json5: 2.2.3 lodash.memoize: 4.1.2 make-error: 1.3.6 - semver: 7.5.4 + semver: 7.6.0 typescript: 5.1.6 yargs-parser: 21.1.1 dev: true @@ -5684,8 +5755,8 @@ packages: engines: {node: '>=14.16'} dev: true - /type-fest@4.9.0: - resolution: {integrity: sha512-KS/6lh/ynPGiHD/LnAobrEFq3Ad4pBzOlJ1wAnJx9N4EYoqFhMfLIBjUT2UEx4wg5ZE+cC1ob6DCSpppVo+rtg==} + /type-fest@4.10.3: + resolution: {integrity: sha512-JLXyjizi072smKGGcZiAJDCNweT8J+AuRxmPZ1aG7TERg4ijx9REl8CNhbr36RV4qXqL1gO1FF9HL8OkVmmrsA==} engines: {node: '>=16'} dev: true @@ -5714,11 +5785,6 @@ packages: resolution: {integrity: sha512-JlCMO+ehdEIKqlFxk6IfVoAUVmgz7cU7zD/h9XZ0qzeosSHmUJVOzSQvvYSYWXkFXC+IfLKSIffhv0sVZup6pA==} dev: true - /universalify@0.1.2: - resolution: {integrity: sha512-rBJeI5CXAlmy1pV+617WB9J63U6XcazHHF2f2dbJix4XzpUF0RS3Zbj0FGIOCAva5P/d/GBOYaACQ1w+0azUkg==} - engines: {node: '>= 4.0.0'} - dev: true - /universalify@0.2.0: resolution: {integrity: sha512-CJ1QgKmNg3CwvAv/kOFmtnEN05f0D/cn9QntgNOQlQF9dgvVTHj3t+8JPdjqawCHk7V/KA+fbUqzZ9XWhcqPUg==} engines: {node: '>= 4.0.0'} @@ -5744,14 +5810,14 @@ packages: setimmediate: 1.0.5 dev: true - /update-browserslist-db@1.0.13(browserslist@4.22.2): + /update-browserslist-db@1.0.13(browserslist@4.23.0): resolution: {integrity: sha512-xebP81SNcPuNpPP3uzeW1NYXxI3rxyJzF3pD6sH4jE7o/IX+WtSpwnVU+qIsDPyk0d3hmFQ7mjqc6AtV604hbg==} hasBin: true peerDependencies: browserslist: '>= 4.21.0' dependencies: - browserslist: 4.22.2 - escalade: 3.1.1 + browserslist: 4.23.0 + escalade: 3.1.2 picocolors: 1.0.0 dev: true @@ -5781,7 +5847,7 @@ packages: resolution: {integrity: sha512-/EH/sDgxU2eGxajKdwLCDmQ4FWq+kpi3uCmBGpw1xJtnAxEjlD8j8PEiGWpCIMIs3ciNAgH0d3TTJiUkYzyZjA==} engines: {node: '>=10.12.0'} dependencies: - '@jridgewell/trace-mapping': 0.3.21 + '@jridgewell/trace-mapping': 0.3.25 '@types/istanbul-lib-coverage': 2.0.6 convert-source-map: 2.0.0 dev: true @@ -5832,7 +5898,7 @@ packages: defaults: 1.0.4 dev: true - /wdio-chromedriver-service@8.1.1(webdriverio@8.27.2): + /wdio-chromedriver-service@8.1.1(webdriverio@8.32.3): resolution: {integrity: sha512-pN3GiOkTIMnalfq4PJAHdX95pDp1orHnTY8W1fIbd6ok81ba97UjerTgS7lUDRUh1p0MAm35Ww0uc0/9wzB7SA==} engines: {node: ^16.13 || >=18} peerDependencies: @@ -5845,31 +5911,31 @@ packages: chromedriver: optional: true dependencies: - '@wdio/logger': 8.24.12 + '@wdio/logger': 8.28.0 fs-extra: 11.2.0 split2: 4.2.0 tcp-port-used: 1.0.2 - webdriverio: 8.27.2(typescript@5.1.6) + webdriverio: 8.32.3(typescript@5.1.6) transitivePeerDependencies: - supports-color dev: true - /web-streams-polyfill@3.3.2: - resolution: {integrity: sha512-3pRGuxRF5gpuZc0W+EpwQRmCD7gRqcDOMt688KmdlDAgAyaB1XlN0zq2njfDNm44XVdIouE7pZ6GzbdyH47uIQ==} + /web-streams-polyfill@3.3.3: + resolution: {integrity: sha512-d2JWLCivmZYTSIoge9MsgFCZrt571BikcWGYkjC1khllbTeDlGqZ2D8vD8E/lJa8WGWbb7Plm8/XJYV7IJHZZw==} engines: {node: '>= 8'} dev: true - /webdriver@8.27.2: - resolution: {integrity: sha512-vY2Lr0ZNr83n0v8PjLCXtJwR9E7QGycJVS+ev2G72gI54/rFwLv58HMSbJNn8CtE27VkhtewMUPlDpSkj5wGPQ==} + /webdriver@8.32.3: + resolution: {integrity: sha512-1/kpZvuftt59oikHs+6FvWXNfOM5tgMMMAk3LnMe7D938dVOoNGAe46fq0oL/xsxxPicbMRTRgIy1OifLiglaA==} engines: {node: ^16.13 || >=18} dependencies: - '@types/node': 20.11.2 + '@types/node': 20.11.24 '@types/ws': 8.5.10 - '@wdio/config': 8.27.2 - '@wdio/logger': 8.24.12 - '@wdio/protocols': 8.24.12 - '@wdio/types': 8.27.2 - '@wdio/utils': 8.27.2 + '@wdio/config': 8.32.3 + '@wdio/logger': 8.28.0 + '@wdio/protocols': 8.32.0 + '@wdio/types': 8.32.2 + '@wdio/utils': 8.32.3 deepmerge-ts: 5.1.0 got: 12.6.1 ky: 0.33.3 @@ -5880,8 +5946,8 @@ packages: - utf-8-validate dev: true - /webdriverio@8.27.2(typescript@5.1.6): - resolution: {integrity: sha512-X6PhKE8e8XsB33Q/KSS1zYKP2Rqkq2Nef0YKOhQO+5OTlTkeqMCjnEtyRcfmdtfAwT0DEFqMnGnUKEbTajFC4Q==} + /webdriverio@8.32.3(typescript@5.1.6): + resolution: {integrity: sha512-SupbQKMtUZHSH7lmF5xaJPgxsn8sIBNAjs1CyPI33u30eY9VcVQ4CJQ818ZS3FLxR0q2XdWk9lsQNyhZwlN3RA==} engines: {node: ^16.13 || >=18} peerDependencies: devtools: ^8.14.0 @@ -5889,18 +5955,18 @@ packages: devtools: optional: true dependencies: - '@types/node': 20.11.2 - '@wdio/config': 8.27.2 - '@wdio/logger': 8.24.12 - '@wdio/protocols': 8.24.12 + '@types/node': 20.11.24 + '@wdio/config': 8.32.3 + '@wdio/logger': 8.28.0 + '@wdio/protocols': 8.32.0 '@wdio/repl': 8.24.12 - '@wdio/types': 8.27.2 - '@wdio/utils': 8.27.2 - archiver: 6.0.1 + '@wdio/types': 8.32.2 + '@wdio/utils': 8.32.3 + archiver: 6.0.2 aria-query: 5.3.0 css-shorthand-properties: 1.1.1 css-value: 0.0.1 - devtools-protocol: 0.0.1239539 + devtools-protocol: 0.0.1262051 grapheme-splitter: 1.0.4 import-meta-resolve: 4.0.0 is-plain-obj: 4.1.0 @@ -5912,7 +5978,7 @@ packages: resq: 1.11.0 rgb2hex: 0.2.5 serialize-error: 11.0.3 - webdriver: 8.27.2 + webdriver: 8.32.3 transitivePeerDependencies: - bufferutil - encoding @@ -6093,7 +6159,7 @@ packages: engines: {node: '>=10'} dependencies: cliui: 7.0.4 - escalade: 3.1.1 + escalade: 3.1.2 get-caller-file: 2.0.5 require-directory: 2.1.1 string-width: 4.2.3 @@ -6106,7 +6172,7 @@ packages: engines: {node: '>=12'} dependencies: cliui: 8.0.1 - escalade: 3.1.1 + escalade: 3.1.2 get-caller-file: 2.0.5 require-directory: 2.1.1 string-width: 4.2.3 @@ -6119,7 +6185,7 @@ packages: engines: {node: '>=12'} dependencies: cliui: 8.0.1 - escalade: 3.1.1 + escalade: 3.1.2 get-caller-file: 2.0.5 require-directory: 2.1.1 string-width: 4.2.3 @@ -6144,11 +6210,11 @@ packages: engines: {node: '>=12.20'} dev: true - /zip-stream@5.0.1: - resolution: {integrity: sha512-UfZ0oa0C8LI58wJ+moL46BDIMgCQbnsb+2PoiJYtonhBsMh2bq1eRBVkvjfVsqbEHd9/EgKPUuL9saSSsec8OA==} + /zip-stream@5.0.2: + resolution: {integrity: sha512-LfOdrUvPB8ZoXtvOBz6DlNClfvi//b5d56mSWyJi7XbH/HfhOHfUhOqxhT/rUiR7yiktlunqRo+jY6y/cWC/5g==} engines: {node: '>= 12.0.0'} dependencies: archiver-utils: 4.0.1 - compress-commons: 5.0.1 + compress-commons: 5.0.3 readable-stream: 3.6.2 dev: true diff --git a/src/gui/FlashcardModal.tsx b/src/gui/FlashcardModal.tsx index eba110cb..9ff4b372 100644 --- a/src/gui/FlashcardModal.tsx +++ b/src/gui/FlashcardModal.tsx @@ -52,9 +52,6 @@ export class FlashcardModal extends Modal { this.modalEl.setAttribute("id", "sr-modal"); this.contentEl.addClass("sr-modal-content"); - // if (Platform.isMobile) { - // this.contentEl.style.display = "block"; - // } // Init static elements in views this.deckView = new DeckListView( From 8d591fa574f4c6496d92bdf6542b5ade4927ecb5 Mon Sep 17 00:00:00 2001 From: Kyle Klus Date: Wed, 20 Mar 2024 11:39:00 +0100 Subject: [PATCH 36/37] Update changelog.md --- docs/changelog.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/docs/changelog.md b/docs/changelog.md index 67f3c8af..1f621995 100644 --- a/docs/changelog.md +++ b/docs/changelog.md @@ -7,6 +7,8 @@ Generated by [`auto-changelog`](https://github.com/CookPete/auto-changelog). #### [Unreleased] - Overhauled ui as described in issue [`#872`](https://github.com/st3v3nmw/obsidian-spaced-repetition/issues/872) +- Fixes key listener bug from issue #907 +- Fixes bug from issue #773 #### [1.12.0](https://github.com/st3v3nmw/obsidian-spaced-repetition/compare/1.11.2...1.12.0) From 79a724774367e8524d092dc36db15bcdc05a76ad Mon Sep 17 00:00:00 2001 From: KyleKlus Date: Wed, 20 Mar 2024 11:41:40 +0100 Subject: [PATCH 37/37] UPDATE: Added issue links to the changelog & formatted files --- docs/changelog.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/docs/changelog.md b/docs/changelog.md index 1f621995..facc6724 100644 --- a/docs/changelog.md +++ b/docs/changelog.md @@ -7,8 +7,8 @@ Generated by [`auto-changelog`](https://github.com/CookPete/auto-changelog). #### [Unreleased] - Overhauled ui as described in issue [`#872`](https://github.com/st3v3nmw/obsidian-spaced-repetition/issues/872) -- Fixes key listener bug from issue #907 -- Fixes bug from issue #773 +- Fixes key listener bug from issue [`#907`](https://github.com/st3v3nmw/obsidian-spaced-repetition/issues/907) +- Fixes bug from issue [`#773`](https://github.com/st3v3nmw/obsidian-spaced-repetition/issues/773) #### [1.12.0](https://github.com/st3v3nmw/obsidian-spaced-repetition/compare/1.11.2...1.12.0)