obsidian#ButtonComponent TypeScript Examples

The following examples show how to use obsidian#ButtonComponent. You can vote up the ones you like or vote down the ones you don't like, and go to the original project or source file by following the links above each example. You may check out the related API usage on the sidebar.
Example #1
Source File: ImgurAuthModal.ts    From obsidian-imgur-plugin with MIT License 6 votes vote down vote up
onOpen(): void {
    this.opened = true;

    this.timerDiv = this.modalEl.createDiv();
    this.updateText();

    this.intervalId = setInterval(() => {
      this.secondsLeft -= 1;
      this.updateText();

      if (this.secondsLeft === 0) {
        window.open(this.authLink);
        clearInterval(this.intervalId);
      }
    }, ONE_SECOND_MILLIS);
    this.addNoWaitDiv(this.intervalId);

    new ButtonComponent(this.modalEl.createDiv())
      .setButtonText("Cancel")
      .setCta()
      .onClick(() => this.close());
  }
Example #2
Source File: confirm.ts    From obsidian-admonition with MIT License 6 votes vote down vote up
async display() {
        this.contentEl.empty();
        this.contentEl.addClass("confirm-modal");
        this.contentEl.createEl("p", {
            text: this.text
        });
        const buttonEl = this.contentEl.createDiv(
            "fantasy-calendar-confirm-buttons"
        );
        new ButtonComponent(buttonEl)
            .setButtonText(this.buttons.cta)
            .setCta()
            .onClick(() => {
                this.confirmed = true;
                this.close();
            });
        new ButtonComponent(buttonEl)
            .setButtonText(this.buttons.secondary)
            .onClick(() => {
                this.close();
            });
    }
Example #3
Source File: main.ts    From obsidian-readwise with GNU General Public License v3.0 6 votes vote down vote up
async acknowledgeSyncCompleted(buttonContext: ButtonComponent) {
    let response;
    try {
      response = await fetch(
        `${baseURL}/api/obsidian/sync_ack`,
        {
          headers: {...this.getAuthHeaders(), 'Content-Type': 'application/json'},
          method: "POST",
        });
    } catch (e) {
      console.log("Readwise Official plugin: fetch failed to acknowledged sync: ", e);
    }
    if (response && response.ok) {
      return;
    } else {
      console.log("Readwise Official plugin: bad response in acknowledge sync: ", response);
      this.handleSyncError(buttonContext, this.getErrorMessageFromResponse(response));
      return;
    }
  }
Example #4
Source File: valueSelectModal.ts    From obsidian_supercharged_links with MIT License 6 votes vote down vote up
buildInputEl(inputDiv: HTMLDivElement): void{
        const selectEl = new DropdownComponent(inputDiv)
        selectEl.selectEl.addClass("frontmatter-select")
        const values = this.settings.values
        selectEl.addOption("","--Empty--")
        Object.keys(values).forEach(key => {
            selectEl.addOption(values[key], values[key])
        });
        if(Object.values(values).includes(this.value)){
            selectEl.setValue(this.value)
        }
        FieldSetting.getValuesListFromNote(this.settings.valuesListNotePath, this.app).then(listNoteValues => {
            listNoteValues.forEach(value => selectEl.addOption(value, value))
            if(listNoteValues.includes(this.value)){
                selectEl.setValue(this.value)
            }
            selectEl.onChange(value => this.newValue = value != "--Empty--" ? value : "")
            const submitButton = new ButtonComponent(inputDiv)
            submitButton.setTooltip("Save")
            .setIcon("checkmark")
            .onClick(async () => {
                if(this.lineNumber == -1){
                    if(this.newValue || this.newValue == ""){
                        replaceValues(this.app, this.file, this.name, this.newValue)
                    }
                } else {
                    this.app.vault.read(this.file).then(result => {
                        let newContent: string[] = []
                        if(this.top){
                            newContent.push(`${this.name}${this.inFrontmatter ? ":" : "::"} ${selectEl.getValue()}`)
                            result.split("\n").forEach((line, _lineNumber) => newContent.push(line))
                        } else {
                            result.split("\n").forEach((line, _lineNumber) => {
                                newContent.push(line)
                                if(_lineNumber == this.lineNumber){
                                    newContent.push(`${this.name}${this.inFrontmatter ? ":" : "::"} ${selectEl.getValue()}`)
                                }
                            })
                        }
                        this.app.vault.modify(this.file, newContent.join('\n'))
                        this.close()
                    })
                }
                this.close()
            })
        })
        
    }
Example #5
Source File: settings.ts    From obsidian-initiative-tracker with GNU General Public License v3.0 6 votes vote down vote up
async display() {
        new Promise((resolve) => {
            this.contentEl.empty();
            this.contentEl.addClass("confirm-modal");
            this.contentEl.createEl("p", {
                text: this.text
            });
            const buttonEl = this.contentEl.createDiv(
                "fantasy-calendar-confirm-buttons"
            );
            new ButtonComponent(buttonEl)
                .setButtonText(this.buttons.cta)
                .setCta()
                .onClick(() => {
                    this.confirmed = true;
                    this.close();
                });
            new ButtonComponent(buttonEl)
                .setButtonText(this.buttons.secondary)
                .onClick(() => {
                    this.close();
                });
        });
    }
Example #6
Source File: RemoteUploadConfirmationDialog.ts    From obsidian-imgur-plugin with MIT License 6 votes vote down vote up
onOpen(): void {
    this.titleEl.setText("Imgur plugin");
    this.contentEl.setText(
      "Would you like to upload to Imgur or paste your content locally?"
    );

    const buttonsDiv = this.modalEl.createDiv("modal-button-container");

    new ButtonComponent(buttonsDiv)
      .setButtonText("Always upload")
      .setCta()
      .onClick(() => {
        this.deferredResolve({ shouldUpload: true, alwaysUpload: true });
        this.afterUserInput();
      });

    new ButtonComponent(buttonsDiv)
      .setButtonText("Upload")
      .setCta()
      .onClick(() => {
        this.deferredResolve({ shouldUpload: true });
        this.afterUserInput();
      });

    new ButtonComponent(buttonsDiv)
      .setButtonText("Paste locally")
      .onClick(() => {
        this.deferredResolve({ shouldUpload: false });
        this.afterUserInput();
      });
  }
Example #7
Source File: view.ts    From obsidian-fantasy-calendar with MIT License 6 votes vote down vote up
async display() {
        this.contentEl.empty();
        this.contentEl.createEl("h4", { text: "View Day" });
        this.dateFieldEl = this.contentEl.createDiv(
            "fantasy-calendar-date-fields"
        );
        this.buildDateFields();

        new Setting(this.contentEl)
            .setName("Set as Current Date")
            .setDesc("Also set this date to today's date.")
            .addToggle((t) =>
                t.setValue(this.setCurrent).onChange((v) => {
                    this.setCurrent = v;
                })
            );

        const buttonEl = this.contentEl.createDiv(
            "fantasy-calendar-confirm-buttons"
        );

        new ButtonComponent(buttonEl)
            .setButtonText("Switch")
            .setCta()
            .onClick(() => {
                this.confirmed = true;
                this.date.day = this.tempCurrentDays;
                this.close();
            });
        new ButtonComponent(buttonEl).setButtonText("Cancel").onClick(() => {
            this.close();
        });
    }
Example #8
Source File: MacrosManager.ts    From quickadd with MIT License 6 votes vote down vote up
private addAddMacroBar() {
        const addMacroBarContainer: HTMLDivElement = this.contentEl.createDiv();
        addMacroBarContainer.addClass("addMacroBarContainer");

        const nameInput: TextComponent = new TextComponent(addMacroBarContainer);
        nameInput.setPlaceholder("Macro name");

        const addMacroButton: ButtonComponent = new ButtonComponent(addMacroBarContainer);
        addMacroButton.setButtonText("Add macro")
            .setClass("mod-cta")
            .onClick(() => {
                const inputValue = nameInput.getValue();

                if (inputValue !== "" && !this.macros.find(m => m.name === inputValue)) {
                    const macro = new QuickAddMacro(inputValue);
                    if (!macro) {
                        log.logError("macro invalid - will not be added");
                        return;
                    }


                    this.macros.push(macro);
                    this.reload();
                    this.macroContainer.scrollTo(0, this.macroContainer.scrollHeight);
                }
            })
    }
Example #9
Source File: settings.ts    From folder-note-core with MIT License 5 votes vote down vote up
private addButton(cb: (component: ButtonComponent) => any): ButtonComponent {
    const button = new ButtonComponent(this.buttonContainerEl);
    cb(button);
    return button;
  }
Example #10
Source File: MacrosManager.ts    From quickadd with MIT License 5 votes vote down vote up
private addMacroSetting(macro: IMacro, container: HTMLDivElement) {
        const configureMacroContainer = container.createDiv();

        const macroSetting: Setting = new Setting(configureMacroContainer);
        macroSetting.setName(macro.name);
        macroSetting.infoEl.style.fontWeight = "bold";

        this.addMacroConfigurationItem(configureMacroContainer, itemContainerEl => {
            this.addSpanWithText(itemContainerEl, "Run on plugin load");

            const toggle: ToggleComponent = new ToggleComponent(itemContainerEl);
            toggle.setValue(macro.runOnStartup);

            toggle.onChange(value => {
                macro.runOnStartup = value;

                this.updateMacro(macro);
            });
        });

        configureMacroContainer.addClass("configureMacroDiv");
        this.addMacroConfigurationItem(configureMacroContainer, itemContainerEl => {
            const deleteButton: ButtonComponent = new ButtonComponent(itemContainerEl);
            deleteButton.setClass('mod-warning');
            deleteButton.buttonEl.style.marginRight = "0";

            deleteButton.setButtonText("Delete").onClick(evt => {
                this.macros = this.macros.filter(m => m.id !== macro.id);
                const scroll: number = this.macroContainer.scrollTop;

                this.reload();

                this.macroContainer.scrollTop = scroll;
            });

            const configureButton: ButtonComponent = new ButtonComponent(itemContainerEl);
            configureButton.setClass('mod-cta');
            configureButton.buttonEl.style.marginRight = "0";

            configureButton.setButtonText("Configure").onClick(async evt => {
                const getReachableChoices = (choices: IChoice[]) => {
                    let reachableChoices: IChoice[] = [];
                    choices.forEach(choice => {
                        if (choice.type === ChoiceType.Multi)
                            reachableChoices.push(...getReachableChoices((<IMultiChoice>choice).choices));

                        if (choice.type !== ChoiceType.Multi)
                            reachableChoices.push(choice);
                    })
                    return reachableChoices;
                }

                const reachableChoices = getReachableChoices(this.choices);
                const newMacro = await new MacroBuilder(this.app, this.plugin, macro, reachableChoices).waitForClose;

                if (newMacro) {
                    this.updateMacro(newMacro);
                    this.reload();
                }
            });
        });

    }
Example #11
Source File: main.ts    From obsidian-readwise with GNU General Public License v3.0 5 votes vote down vote up
async requestArchive(buttonContext?: ButtonComponent, statusId?: number, auto?: boolean) {

    const parentDeleted = !await this.app.vault.adapter.exists(this.settings.readwiseDir);

    let url = `${baseURL}/api/obsidian/init?parentPageDeleted=${parentDeleted}`;
    if (statusId) {
      url += `&statusID=${statusId}`;
    }
    if (auto) {
      url += `&auto=${auto}`;
    }
    let response, data: ExportRequestResponse;
    try {
      response = await fetch(
        url,
        {
          headers: this.getAuthHeaders()
        }
      );
    } catch (e) {
      console.log("Readwise Official plugin: fetch failed in requestArchive: ", e);
    }
    if (response && response.ok) {
      data = await response.json();
      if (data.latest_id <= this.settings.lastSavedStatusID) {
        this.handleSyncSuccess(buttonContext);
        this.notice("Readwise data is already up to date", false, 4, true);
        return;
      }
      this.settings.currentSyncStatusID = data.latest_id;
      await this.saveSettings();
      if (response.status === 201) {
        this.notice("Syncing Readwise data");
        return this.getExportStatus(data.latest_id, buttonContext);
      } else {
        this.handleSyncSuccess(buttonContext, "Synced", data.latest_id); // we pass the export id to update lastSavedStatusID
        this.notice("Latest Readwise sync already happened on your other device. Data should be up to date", false, 4, true);
      }
    } else {
      console.log("Readwise Official plugin: bad response in requestArchive: ", response);
      this.handleSyncError(buttonContext, this.getErrorMessageFromResponse(response));
      return;
    }
  }
Example #12
Source File: templateChoiceBuilder.ts    From quickadd with MIT License 5 votes vote down vote up
private addFolderSelector() {
        const folderSelectionContainer: HTMLDivElement = this.contentEl.createDiv('folderSelectionContainer');
        const folderList: HTMLDivElement = folderSelectionContainer.createDiv('folderList');

        const folderListEl = new FolderList({
            target: folderList,
            props: {
                folders: this.choice.folder.folders,
                deleteFolder: (folder: string) => {
                    this.choice.folder.folders = this.choice.folder.folders.filter(f => f !== folder);
                    folderListEl.updateFolders(this.choice.folder.folders);
                    suggester.updateCurrentItems(this.choice.folder.folders);
                }
            }
        });

        this.svelteElements.push(folderListEl);

        const inputContainer = folderSelectionContainer.createDiv('folderInputContainer');
        const folderInput = new TextComponent(inputContainer);
        folderInput.inputEl.style.width = "100%";
        folderInput.setPlaceholder("Folder path");
        const allFolders: string[] = getAllFolderPathsInVault(this.app);

        const suggester = new ExclusiveSuggester(this.app, folderInput.inputEl, allFolders, this.choice.folder.folders);

        const addFolder = () => {
            const input = folderInput.inputEl.value.trim();

            if (this.choice.folder.folders.some(folder => folder === input)) {
                log.logWarning("cannot add same folder twice.");
                return;
            }

            this.choice.folder.folders.push(input);
            folderListEl.updateFolders(this.choice.folder.folders);
            folderInput.inputEl.value = "";

            suggester.updateCurrentItems(this.choice.folder.folders);
        }

        folderInput.inputEl.addEventListener('keypress', (e: KeyboardEvent) => {
            if (e.key === 'Enter') {
                addFolder();
            }
        });

        const addButton: ButtonComponent = new ButtonComponent(inputContainer);
        addButton.setCta().setButtonText("Add").onClick(evt => {
            addFolder();
        });
    }
Example #13
Source File: FieldSettingsModal.ts    From obsidian_supercharged_links with MIT License 5 votes vote down vote up
createSaveButton(b: ButtonComponent): ButtonComponent {
        b.setTooltip("Save")
            .setIcon("checkmark")
            .onClick(async () => {
                let error = false
                if (/^[#>-]/.test(this.property.name)) {
                    FieldSettingsModal.setValidationError(
                        this.namePromptComponent, this.namePromptComponent.inputEl,
                        "Property name cannot start with #, >, -"
                    );
                    error = true;
                }
                if (this.property.name == "") {
                    FieldSettingsModal.setValidationError(
                        this.namePromptComponent, this.namePromptComponent.inputEl,
                        "Property name can not be Empty"
                    );
                    error = true
                }
                this.valuesPromptComponents.forEach(input => {
                    if (/^[#>-]/.test(input.inputEl.value)) {
                        FieldSettingsModal.setValidationError(
                            input, input.inputEl.parentElement.lastElementChild,
                            "Values cannot cannot start with #, >, -"
                        );
                        error = true;
                    }
                    if (/[,]/gu.test(input.inputEl.value)) {
                        FieldSettingsModal.setValidationError(
                            input, input.inputEl.parentElement.lastElementChild,
                            "Values cannot contain a comma"
                        );
                        error = true;
                    }
                    if (input.inputEl.value == "") {
                        FieldSettingsModal.setValidationError(
                            input, input.inputEl.parentElement.lastElementChild,
                            "Values can't be null."
                        );
                        error = true;
                    }
                })
                if (error) {
                    new Notice("Fix errors before saving.");
                    return;
                }
                this.saved = true;
                const currentExistingProperty = this.plugin.initialProperties.filter(p => p.id == this.property.id)[0]
                if (currentExistingProperty) {
                    Field.copyProperty(currentExistingProperty, this.property)
                } else {
                    this.plugin.initialProperties.push(this.property)
                }
                this.initialProperty = this.property
                this.plugin.saveSettings()
                this.close();
            })
        return b
    }
Example #14
Source File: GenericInputPrompt.ts    From quickadd with MIT License 5 votes vote down vote up
private createButton(container: HTMLElement, text: string, callback: (evt: MouseEvent) => any) {
        const btn = new ButtonComponent(container);
        btn.setButtonText(text)
            .onClick(callback);

        return btn;
    }
Example #15
Source File: addNewFieldModal.ts    From obsidian_supercharged_links with MIT License 5 votes vote down vote up
onOpen(){
        this.titleEl.setText("Insert new field")
        const addNewFieldContainer = this.contentEl.createDiv()
        const nameInputContainer = addNewFieldContainer.createDiv()
        nameInputContainer.setText("Field Name: ")
        const nameInputEl = new TextComponent(nameInputContainer)
        nameInputEl.setPlaceholder("Field name")
        const valueInputContainer = addNewFieldContainer.createDiv()
        valueInputContainer.setText("Field value: ")
        const valueInputEl = new TextComponent(valueInputContainer)
        valueInputEl.setPlaceholder("Field value")
        const footerButtons = this.contentEl.createDiv({
            cls: 'frontmatter-textarea-buttons'
        })
        const saveButton = new ButtonComponent(footerButtons)
        saveButton.setIcon("checkmark")
        saveButton.onClick(() => {
            this.app.vault.read(this.file).then(result => {
                let newContent: string[] = []
                if(this.top){
                    newContent.push(`${nameInputEl.getValue()}${this.inFrontmatter ? ":" : "::"} ${valueInputEl.getValue()}`)
                    result.split("\n").forEach((line, _lineNumber) => newContent.push(line))
                } else {
                    result.split("\n").forEach((line, _lineNumber) => {
                        newContent.push(line)
                        if(_lineNumber == this.lineNumber){
                            newContent.push(`${nameInputEl.getValue()}${this.inFrontmatter ? ":" : "::"} ${valueInputEl.getValue()}`)
                        }
                    })
                }
                this.app.vault.modify(this.file, newContent.join('\n'))
                this.close()
            })
        })
        const cancelButton = new ExtraButtonComponent(footerButtons)
        cancelButton.setIcon("cross")
        cancelButton.onClick(() => {
            this.close()
        })


    }
Example #16
Source File: GenericWideInputPrompt.ts    From quickadd with MIT License 5 votes vote down vote up
private createButton(container: HTMLElement, text: string, callback: (evt: MouseEvent) => any) {
        const btn = new ButtonComponent(container);
        btn.setButtonText(text)
            .onClick(callback);

        return btn;
    }
Example #17
Source File: viewControls.ts    From obsidian-map-view with GNU General Public License v3.0 5 votes vote down vote up
refreshPresets() {
        if (this.presetsDivContent) this.presetsDivContent.remove();
        this.presetsDivContent = this.presetsDiv.createDiv({
            cls: 'graph-control-content',
        });
        this.presetsBox = new DropdownComponent(this.presetsDivContent);
        const states = [
            this.settings.defaultState,
            ...(this.settings.savedStates || []),
        ];
        this.presetsBox.addOption('-1', '');
        for (const [index, preset] of states.entries()) {
            this.presetsBox.addOption(index.toString(), preset.name);
        }
        if (
            this.lastSelectedPresetIndex &&
            this.lastSelectedPresetIndex < states.length &&
            areStatesEqual(this.getCurrentState(), this.lastSelectedPreset)
        )
            this.presetsBox.setValue(this.lastSelectedPreset.toString());
        this.presetsBox.onChange(async (value: string) => {
            const chosenPresetNumber = parseInt(value);
            if (chosenPresetNumber == -1) return;
            await this.choosePresetAndUpdateState(chosenPresetNumber);
        });
        let savePreset = new ButtonComponent(this.presetsDivContent);
        savePreset
            .setButtonText('Save as...')
            .setTooltip('Save the current view as a preset.')
            .onClick(() => {
                const dialog = new NewPresetDialog(
                    this.app,
                    this.getCurrentState(),
                    this.plugin,
                    this.settings,
                    (index: string) => {
                        // If a new preset was added, this small function makes sure it's selected afterwards
                        this.refreshPresets();
                        if (index) this.presetsBox.setValue(index);
                    }
                );
                dialog.open();
            });
        let deletePreset = new ButtonComponent(this.presetsDivContent);
        deletePreset
            .setButtonText('Delete')
            .setTooltip('Delete the currently-selected preset.')
            .onClick(async () => {
                const selectionIndex = parseInt(this.presetsBox.getValue());
                if (selectionIndex > 0) {
                    this.settings.savedStates.splice(selectionIndex - 1, 1);
                    await this.plugin.saveSettings();
                    this.refreshPresets();
                }
            });
        let saveAsDefault = new ButtonComponent(this.presetsDivContent);
        saveAsDefault
            .setButtonText('Save as Default')
            .setTooltip('Save the current view as the default one.')
            .onClick(async () => {
                this.settings.defaultState = {
                    ...this.getCurrentState(),
                    name: 'Default',
                };
                await this.plugin.saveSettings();
                this.presetsBox.setValue('0');
            });
        new ButtonComponent(this.presetsDivContent)
            .setButtonText('Copy URL')
            .setTooltip('Copy the current view as a URL.')
            .onClick(async () => {
                this.view.copyStateUrl();
            });
    }
Example #18
Source File: ItemModal.ts    From obsidian-rss with GNU General Public License v3.0 5 votes vote down vote up
private favoriteButton: ButtonComponent;
Example #19
Source File: settings.ts    From obsidian-initiative-tracker with GNU General Public License v3.0 5 votes vote down vote up
onOpen() {
        this.titleEl.setText(this.editing ? "Edit Status" : "New Status");

        const name = new Setting(this.contentEl)
            .setName("Name")
            .addText((t) => {
                t.setValue(this.status.name).onChange((v) => {
                    this.status.name = v;
                    if (
                        this.plugin.data.statuses.find(
                            (s) => s.name == this.status.name
                        ) &&
                        !this.warned &&
                        this.original != this.status.name
                    ) {
                        this.warned = true;
                        name.setDesc(
                            createFragment((e) => {
                                const container = e.createDiv(
                                    "initiative-tracker-warning"
                                );
                                setIcon(
                                    container,
                                    "initiative-tracker-warning"
                                );
                                container.createSpan({
                                    text: "A status by this name already exists and will be overwritten."
                                });
                            })
                        );
                    } else if (this.warned) {
                        this.warned = false;
                        name.setDesc("");
                    }
                });
            });
        new Setting(this.contentEl).setName("Description").addTextArea((t) => {
            t.setValue(this.status.description).onChange(
                (v) => (this.status.description = v)
            );
        });

        new ButtonComponent(
            this.contentEl.createDiv("initiative-tracker-cancel")
        )
            .setButtonText("Cancel")
            .onClick(() => {
                this.canceled = true;
                this.close();
            });
    }
Example #20
Source File: MacroBuilder.ts    From quickadd with MIT License 5 votes vote down vote up
private addAddWaitCommandButton(quickCommandContainer: HTMLDivElement) {
        const button: ButtonComponent = new ButtonComponent(quickCommandContainer);
        button.setIcon('clock').setTooltip("Add wait command").onClick(() => {
            this.addCommandToMacro(new WaitCommand(100));
        });
    }
Example #21
Source File: viewControls.ts    From obsidian-map-view with GNU General Public License v3.0 5 votes vote down vote up
createControls() {
        this.controlsDiv = createDiv({
            cls: 'graph-controls',
        });
        let filtersDiv = this.controlsDiv.createDiv({
            cls: 'graph-control-div',
        });
        filtersDiv.innerHTML = `
			<input id="filtersCollapsible" class="controls-toggle" type="checkbox">
			<label for="filtersCollapsible" class="lbl-triangle">▸</label>
			<label for="filtersCollapsible" class="lbl-toggle">Filters</label>
			`;
        const filtersButton = filtersDiv.getElementsByClassName(
            'controls-toggle'
        )[0] as HTMLInputElement;
        filtersButton.checked = this.settings.mapControls.filtersDisplayed;
        filtersButton.onclick = async () => {
            this.settings.mapControls.filtersDisplayed = filtersButton.checked;
            this.plugin.saveSettings();
        };
        let filtersContent = filtersDiv.createDiv({
            cls: 'graph-control-content',
        });
        // Wrapping the query box in a div so we can place a button in the right-middle of it
        const queryDiv = filtersContent.createDiv('search-input-container');
        queryDiv.style.margin = '0';
        this.queryBox = new TextComponent(queryDiv);
        this.queryBox.setPlaceholder('Query');
        this.queryBox.onChange((query: string) => {
            this.setStateByQueryString(query);
        });
        let suggestor: QuerySuggest = null;
        this.queryBox.inputEl.addEventListener('focus', (ev: FocusEvent) => {
            if (!suggestor) {
                suggestor = new QuerySuggest(this.app, this.queryBox);
                suggestor.open();
            }
        });
        this.queryBox.inputEl.addEventListener('focusout', (ev: FocusEvent) => {
            if (suggestor) {
                suggestor.close();
                suggestor = null;
            }
        });
        let clearButton = queryDiv.createDiv('search-input-clear-button');
        clearButton.onClickEvent((ev) => {
            this.queryBox.setValue('');
            this.setStateByQueryString('');
        });

        let viewDiv = this.controlsDiv.createDiv({ cls: 'graph-control-div' });
        viewDiv.innerHTML = `
			<input id="viewCollapsible" class="controls-toggle" type="checkbox">
			<label for="viewCollapsible" class="lbl-triangle">▸</label>
			<label for="viewCollapsible" class="lbl-toggle">View</label>
			`;
        const viewButton = viewDiv.getElementsByClassName(
            'controls-toggle'
        )[0] as HTMLInputElement;
        viewButton.checked = this.settings.mapControls.viewDisplayed;
        viewButton.onclick = async () => {
            this.settings.mapControls.viewDisplayed = viewButton.checked;
            this.plugin.saveSettings();
        };
        let viewDivContent = viewDiv.createDiv({
            cls: 'graph-control-content',
        });
        this.mapSourceBox = new DropdownComponent(viewDivContent);
        for (const [index, source] of this.settings.mapSources.entries()) {
            this.mapSourceBox.addOption(index.toString(), source.name);
        }
        this.mapSourceBox.onChange(async (value: string) => {
            this.setStateByNewMapSource(parseInt(value));
        });
        this.setMapSourceBoxByState();
        this.sourceMode = new DropdownComponent(viewDivContent);
        this.sourceMode
            .addOptions({ auto: 'Auto', light: 'Light', dark: 'Dark' })
            .setValue(this.settings.chosenMapMode ?? 'auto')
            .onChange(async (value) => {
                this.settings.chosenMapMode = value as MapLightDark;
                await this.plugin.saveSettings();
                this.view.refreshMap();
            });
        let goDefault = new ButtonComponent(viewDivContent);
        goDefault
            .setButtonText('Reset')
            .setTooltip('Reset the view to the defined default.')
            .onClick(async () => {
                this.presetsBox.setValue('0');
                await this.choosePresetAndUpdateState(0);
                this.updateControlsToState();
            });
        let fitButton = new ButtonComponent(viewDivContent);
        fitButton
            .setButtonText('Fit')
            .setTooltip(
                'Set the map view to fit all currently-displayed markers.'
            )
            .onClick(() => this.view.autoFitMapToMarkers());
        const followDiv = viewDivContent.createDiv({
            cls: 'graph-control-follow-div',
        });
        this.followActiveNoteToggle = new ToggleComponent(followDiv);
        const followLabel = followDiv.createEl('label');
        followLabel.className = 'graph-control-follow-label';
        followLabel.addEventListener('click', () =>
            this.followActiveNoteToggle.onClick()
        );
        followLabel.innerHTML = 'Follow active note';
        this.followActiveNoteToggle.onChange((value) => {
            this.setStateByFollowActiveNote(value);
        });

        this.presetsDiv = this.controlsDiv.createDiv({
            cls: 'graph-control-div',
        });
        this.presetsDiv.innerHTML = `
			<input id="presetsCollapsible" class="controls-toggle" type="checkbox">
			<label for="presetsCollapsible" class="lbl-triangle">▸</label>
			<label for="presetsCollapsible" class="lbl-toggle">Presets</label>
			`;
        const presetsButton = this.presetsDiv.getElementsByClassName(
            'controls-toggle'
        )[0] as HTMLInputElement;
        presetsButton.checked = this.settings.mapControls.presetsDisplayed;
        presetsButton.onclick = async () => {
            this.settings.mapControls.presetsDisplayed = presetsButton.checked;
            this.plugin.saveSettings();
        };
        this.refreshPresets();

        this.parentElement.append(this.controlsDiv);
    }
Example #22
Source File: FeedSettings.ts    From obsidian-rss with GNU General Public License v3.0 5 votes vote down vote up
export function displayFeedSettings(plugin: RssReaderPlugin, container: HTMLElement): void {

    container.empty();

    container.createEl("h3", {text: t("feeds")});

    new Setting(container)
        .setName(t("add_new"))
        .setDesc(t("add_new_feed"))
        .addButton((button: ButtonComponent) => {
            return button
                .setTooltip(t("add_new_feed"))
                .setIcon("plus")
                .onClick(async () => {
                    const modal = new FeedModal(plugin);

                    modal.onClose = async () => {
                        if (modal.saved) {
                            if (plugin.settings.feeds.some(item => item.url === modal.url)) {
                                new Notice(t("feed_already_configured"));
                                return;
                            }
                            await plugin.writeFeeds(() => (
                                plugin.settings.feeds.concat({
                                        name: modal.name,
                                        url: modal.url,
                                        folder: modal.folder ? modal.folder : ""
                                    }
                                )));
                            displayFeedSettings(plugin, container);
                        }
                    };

                    modal.open();
                });
        })
        .addExtraButton(async (button) => {
            button
                .setTooltip(t("import_opml"))
                .setIcon("download")
                .onClick(() => {
                    const modal = new ImportModal(plugin);
                    modal.onClose = () => {
                        displayFeedSettings(plugin, container);
                    };
                    modal.open();
                });
        })
        .addExtraButton(async (button) => {
            button
                .setTooltip(t("export_opml"))
                .setIcon("upload")
                .onClick(() => {
                    if (plugin.app.vault.adapter.exists("rss-feeds-export.opml")) {
                        plugin.app.vault.adapter.remove("rss-feeds-export.opml");
                    }
                    plugin.app.vault.create("rss-feeds-export.opml", generateOPML(plugin.settings.feeds));
                    new Notice(t("created_export"));

                });
        })
        .addExtraButton(async (button) => {
            button
                .setTooltip(t("perform_cleanup"))
                .setIcon("lucide-trash")
                .onClick(() => {
                    new CleanupModal(plugin).open();
                });
        });
    const feedsDiv = container.createDiv("feeds");
    displayFeedList(plugin, feedsDiv);
}
Example #23
Source File: MathModal.ts    From quickadd with MIT License 5 votes vote down vote up
private createButton(container: HTMLElement, text: string, callback: (evt: MouseEvent) => any) {
        const btn = new ButtonComponent(container);
        btn.setButtonText(text)
            .onClick(callback);

        return btn;
    }
Example #24
Source File: newPresetDialog.ts    From obsidian-map-view with GNU General Public License v3.0 5 votes vote down vote up
onOpen() {
        let statusLabel: HTMLDivElement = null;
        const grid = this.contentEl.createDiv({ cls: 'newPresetDialogGrid' });
        const row1 = grid.createDiv({ cls: 'newPresetDialogLine' });
        const row2 = grid.createDiv({ cls: 'newPresetDialogLine' });
        const row3 = grid.createDiv({ cls: 'newPresetDialogLine' });
        let name = new TextComponent(row1).onChange((value) => {
            if (value == 'Default' || value.length === 0)
                saveButton.disabled = true;
            else saveButton.disabled = false;
            if (this.findPresetByName(value))
                statusLabel.setText(
                    "Clicking 'Save' will overwrite an existing preset."
                );
            else statusLabel.setText('');
        });
        name.inputEl.style.width = '100%';
        name.inputEl.addEventListener('keypress', (ev: KeyboardEvent) => {
            if (ev.key == 'Enter') saveButton.buttonEl.click();
        });
        const includeMapSource = row2.createEl('input', { type: 'checkbox' });
        includeMapSource.id = 'includeMapSource';
        const includeMapSourceLabel = row2.createEl('label');
        includeMapSourceLabel.setAttribute('for', 'includeMapSource');
        includeMapSourceLabel.textContent = 'Include chosen map source';
        let saveButton = new ButtonComponent(row3)
            .setButtonText('Save')
            .onClick(async () => {
                let existingPreset = this.findPresetByName(name.getValue());
                let newState = { ...this.stateToSave, name: name.getValue() };
                if (!(includeMapSource as HTMLInputElement).checked)
                    newState.chosenMapSource = undefined;
                if (existingPreset) {
                    Object.assign(existingPreset, newState);
                    newState = existingPreset;
                } else {
                    this.settings.savedStates.push(newState);
                }
                await this.plugin.saveSettings();
                // Update the presets list
                const presetIndex = this.settings.savedStates.indexOf(newState);
                // Select the new preset in the view's controls
                this.callback((presetIndex + 1).toString());
                this.close();
            });
        new ButtonComponent(row3).setButtonText('Cancel').onClick(() => {
            this.close();
        });
        statusLabel = row3.createDiv();
        name.onChanged();
        name.inputEl.focus();
    }
Example #25
Source File: preset.ts    From obsidian-fantasy-calendar with MIT License 5 votes vote down vote up
async display() {
        this.containerEl.addClass("fantasy-calendar-choose-preset");
        this.contentEl.empty();
        this.contentEl.createEl("h3", {
            text: "Choose a Preset Calendar"
        });

        const presetEl = this.contentEl.createDiv(
            "fantasy-calendar-preset-container"
        );

        for (const preset of PRESET_CALENDARS) {
            const button = new ButtonComponent(presetEl).onClick(() => {
                this.preset = preset;
                this.display();
            });
            if (this.preset == preset) button.setCta();
            button.buttonEl.createDiv({
                cls: "setting-item-name",
                text: preset.name
            });
            button.buttonEl.createDiv({
                cls: "setting-item-description",
                text: preset.description
            });
        }

        const buttonEl = this.contentEl.createDiv(
            "fantasy-calendar-confirm-buttons"
        );
        new ButtonComponent(buttonEl)
            .setButtonText("Apply")
            .onClick(() => {
                this.saved = true;
                this.preset = copy(this.preset);
                this.preset.id = nanoid(6);
                this.close();
            })
            .setCta();
        new ExtraButtonComponent(buttonEl).setIcon("cross").onClick(() => {
            this.close();
        });
    }
Example #26
Source File: settings.ts    From obsidian-initiative-tracker with GNU General Public License v3.0 4 votes vote down vote up
private _displayParties(additionalContainer: HTMLDetailsElement) {
        additionalContainer.empty();
        additionalContainer.ontoggle = () => {
            this.plugin.data.openState.party = additionalContainer.open;
        };
        const summary = additionalContainer.createEl("summary");
        new Setting(summary).setHeading().setName("Parties");
        summary.createDiv("collapser").createDiv("handle");
        const explanation = additionalContainer.createDiv(
            "initiative-tracker-explanation"
        );
        explanation.createEl("span", {
            text: "Parties allow you to create different groups of your players. Each player can be a member of multiple parties."
        });
        explanation.createEl("br");
        explanation.createEl("br");
        explanation.createEl("span", {
            text: "You can set a default party for encounters to use, or specify the party for the encounter in the encounter block. While running an encounter in the tracker, you can change the active party, allowing you to quickly switch which players are in combat."
        });
        new Setting(additionalContainer)
            .setName("Default Party")
            .setDesc(
                "The tracker will load this party to encounters by default."
            )
            .addDropdown((d) => {
                d.addOption("none", "None");
                for (const party of this.plugin.data.parties) {
                    d.addOption(party.name, party.name);
                }
                d.setValue(this.plugin.data.defaultParty ?? "none");
                d.onChange(async (v) => {
                    this.plugin.data.defaultParty = v == "none" ? null : v;
                    this.plugin.saveSettings();
                });
            });
        new Setting(additionalContainer)
            .setName("Add New Party")
            .addButton((button: ButtonComponent): ButtonComponent => {
                let b = button
                    .setTooltip("Add Party")
                    .setButtonText("+")
                    .onClick(async () => {
                        const modal = new PartyModal(this.plugin);
                        modal.open();
                        modal.onClose = async () => {
                            if (modal.canceled) return;
                            if (!modal.party.name || !modal.party.name.length)
                                return;
                            if (
                                this.plugin.data.parties.filter(
                                    (party) => party.name == modal.party.name
                                )
                            ) {
                                const map = new Map(
                                    [...this.plugin.data.parties].map((c) => [
                                        c.name,
                                        c
                                    ])
                                );
                                map.set(modal.party.name, modal.party);
                                this.plugin.data.parties = Array.from(
                                    map.values()
                                );
                            } else {
                                this.plugin.data.parties.push(modal.party);
                            }

                            await this.plugin.saveSettings();

                            this._displayParties(additionalContainer);
                        };
                    });

                return b;
            });
        const additional = additionalContainer.createDiv("additional");
        if (!this.plugin.data.parties.length) {
            additional
                .createDiv({
                    attr: {
                        style: "display: flex; justify-content: center; padding-bottom: 18px;"
                    }
                })
                .createSpan({
                    text: "No saved parties! Create one to see it here."
                });
        } else {
            for (const party of this.plugin.data.parties) {
                new Setting(additional)
                    .setName(party.name)
                    .setDesc(party.players.join(", "))
                    .addExtraButton((b) => {
                        b.setIcon("pencil").onClick(() => {
                            const modal = new PartyModal(this.plugin, party);
                            modal.open();
                            modal.onClose = async () => {
                                if (modal.canceled) return;
                                if (
                                    !modal.party.name ||
                                    !modal.party.name.length
                                )
                                    return;

                                this.plugin.data.parties.splice(
                                    this.plugin.data.parties.indexOf(party),
                                    1,
                                    modal.party
                                );
                                if (
                                    this.plugin.data.parties.filter(
                                        (s) => s.name == modal.party.name
                                    ).length > 1
                                ) {
                                    if (
                                        this.plugin.data.parties.filter(
                                            (status) =>
                                                status.name == modal.party.name
                                        )
                                    ) {
                                        const map = new Map(
                                            this.plugin.data.parties.map(
                                                (c) => [c.name, c]
                                            )
                                        );
                                        map.set(modal.party.name, modal.party);
                                        this.plugin.data.parties = Array.from(
                                            map.values()
                                        );
                                    }
                                }

                                await this.plugin.saveSettings();

                                this._displayParties(additionalContainer);
                            };
                        });
                    })
                    .addExtraButton((b) => {
                        b.setIcon("trash").onClick(async () => {
                            this.plugin.data.parties =
                                this.plugin.data.parties.filter(
                                    (p) => p.name != party.name
                                );
                            if (this.plugin.data.defaultParty == party.name) {
                                this.plugin.data.defaultParty =
                                    this.plugin.data.parties[0]?.name ?? null;
                            }
                            await this.plugin.saveSettings();
                            this._displayParties(additionalContainer);
                        });
                    });
            }
        }
    }
Example #27
Source File: settings.ts    From obsidian-admonition with MIT License 4 votes vote down vote up
async display(): Promise<void> {
        this.containerEl.empty();
        this.containerEl.addClass("admonition-settings");
        this.containerEl.createEl("h2", { text: t("Admonition Settings") });

        const admonitionEl = this.containerEl.createDiv(
            "admonitions-nested-settings"
        );
        if (!Platform.isMobile) {
            new Setting(admonitionEl)
                .setName("Export Custom Types as CSS")
                .setDesc("Export a CSS snippet for custom callout types.")
                .addButton((b) =>
                    b
                        .setIcon("download")
                        .onClick(() => {
                            const sheet = [
                                `/* This snippet was auto-generated by the Admonitions plugin */\n\n`
                            ];
                            const file = new Blob(
                                [
                                    this.plugin.calloutManager.generateCssString()
                                ],
                                {
                                    type: "text/css"
                                }
                            );
                            createEl("a", {
                                attr: {
                                    download: "custom_callouts.css",
                                    href: URL.createObjectURL(file)
                                }
                            }).click();
                        })
                        .setDisabled(
                            !Object.keys(this.plugin.data.userAdmonitions)
                                .length
                        )
                );
        }

        new Setting(admonitionEl)
            .setName("Use CSS Snippet for Custom Callouts")
            .setDesc(
                "Instead of managing it internally, Admonitions will maintain a CSS snippet to enable your custom types for callouts."
            )
            .addToggle((t) =>
                t.setValue(this.plugin.data.useSnippet).onChange((v) => {
                    this.plugin.data.useSnippet = v;
                    this.plugin.saveSettings();
                    this.plugin.calloutManager.setUseSnippet();
                })
            );

        new Setting(admonitionEl)
            .setName(t("Add New"))
            .setDesc(
                "Add a new Admonition type. All custom Admonitions will also be usable as callouts."
            )
            .addButton((button: ButtonComponent): ButtonComponent => {
                let b = button
                    .setTooltip(t("Add Additional"))
                    .setButtonText("+")
                    .onClick(async () => {
                        let modal = new SettingsModal(this.plugin);

                        modal.onClose = async () => {
                            if (modal.saved) {
                                const admonition = {
                                    type: modal.type,
                                    color: modal.color,
                                    icon: modal.icon,
                                    command: false,
                                    title: modal.title,
                                    injectColor: modal.injectColor,
                                    noTitle: modal.noTitle,
                                    copy: modal.copy
                                };
                                this.plugin.addAdmonition(admonition);

                                this.plugin.calloutManager.addAdmonition(
                                    admonition
                                );
                                this.display();
                            }
                        };

                        modal.open();
                    });

                return b;
            });

        this.additionalEl = admonitionEl.createDiv("additional");
        this.buildTypes();

        this.buildAdmonitions(
            this.containerEl.createEl("details", {
                cls: "admonitions-nested-settings",
                attr: {
                    ...(this.plugin.data.open.admonitions ? { open: true } : {})
                }
            })
        );
        this.buildIcons(
            this.containerEl.createEl("details", {
                cls: "admonitions-nested-settings",
                attr: {
                    ...(this.plugin.data.open.icons ? { open: true } : {})
                }
            })
        );
        this.buildOtherSyntaxes(
            this.containerEl.createEl("details", {
                cls: "admonitions-nested-settings",
                attr: {
                    ...(this.plugin.data.open.other ? { open: true } : {})
                }
            })
        );
        this.buildAdvanced(
            this.containerEl.createEl("details", {
                cls: "admonitions-nested-settings",
                attr: {
                    ...(this.plugin.data.open.advanced ? { open: true } : {})
                }
            })
        );

        const div = this.containerEl.createDiv("coffee");
        div.createEl("a", {
            href: "https://www.buymeacoffee.com/valentine195"
        }).createEl("img", {
            attr: {
                src: "https://img.buymeacoffee.com/button-api/?text=Buy me a coffee&emoji=☕&slug=valentine195&button_colour=e3e7ef&font_colour=262626&font_family=Inter&outline_colour=262626&coffee_colour=ff0000"
            }
        });
    }
Example #28
Source File: Settings.ts    From Templater with GNU Affero General Public License v3.0 4 votes vote down vote up
add_folder_templates_setting(): void {
        this.containerEl.createEl("h2", { text: "Folder Templates" });

        const descHeading = document.createDocumentFragment();
        descHeading.append(
            "Folder Templates are triggered when a new ",
            descHeading.createEl("strong", { text: "empty " }),
            "file is created in a given folder.",
            descHeading.createEl("br"),
            "Templater will fill the empty file with the specified template.",
            descHeading.createEl("br"),
            "The deepest match is used. A global default template would be defined on the root ",
            descHeading.createEl("code", { text: "/" }),
            "."
        );

        new Setting(this.containerEl).setDesc(descHeading);

        const descUseNewFileTemplate = document.createDocumentFragment();
        descUseNewFileTemplate.append(
            "When enabled Templater will make use of the folder templates defined below."
        );

        new Setting(this.containerEl)
            .setName("Enable Folder Templates")
            .setDesc(descUseNewFileTemplate)
            .addToggle((toggle) => {
                toggle
                    .setValue(this.plugin.settings.enable_folder_templates)
                    .onChange((use_new_file_templates) => {
                        this.plugin.settings.enable_folder_templates =
                            use_new_file_templates;
                        this.plugin.save_settings();
                        // Force refresh
                        this.display();
                    });
            });

        if (!this.plugin.settings.enable_folder_templates) {
            return;
        }

        new Setting(this.containerEl)
            .setName("Add New")
            .setDesc("Add new folder template")
            .addButton((button: ButtonComponent) => {
                button
                    .setTooltip("Add additional folder template")
                    .setButtonText("+")
                    .setCta()
                    .onClick(() => {
                        this.plugin.settings.folder_templates.push({
                            folder: "",
                            template: "",
                        });
                        this.plugin.save_settings();
                        this.display();
                    });
            });

        this.plugin.settings.folder_templates.forEach(
            (folder_template, index) => {
                const s = new Setting(this.containerEl)
                    .addSearch((cb) => {
                        new FolderSuggest(this.app, cb.inputEl);
                        cb.setPlaceholder("Folder")
                            .setValue(folder_template.folder)
                            .onChange((new_folder) => {
                                if (
                                    new_folder &&
                                    this.plugin.settings.folder_templates.some(
                                        (e) => e.folder == new_folder
                                    )
                                ) {
                                    log_error(
                                        new TemplaterError(
                                            "This folder already has a template associated with it"
                                        )
                                    );
                                    return;
                                }

                                this.plugin.settings.folder_templates[
                                    index
                                ].folder = new_folder;
                                this.plugin.save_settings();
                            });
                        // @ts-ignore
                        cb.containerEl.addClass("templater_search");
                    })
                    .addSearch((cb) => {
                        new FileSuggest(
                            this.app,
                            cb.inputEl,
                            this.plugin,
                            FileSuggestMode.TemplateFiles
                        );
                        cb.setPlaceholder("Template")
                            .setValue(folder_template.template)
                            .onChange((new_template) => {
                                this.plugin.settings.folder_templates[
                                    index
                                ].template = new_template;
                                this.plugin.save_settings();
                            });
                        // @ts-ignore
                        cb.containerEl.addClass("templater_search");
                    })
                    .addExtraButton((cb) => {
                        cb.setIcon("up-chevron-glyph")
                            .setTooltip("Move up")
                            .onClick(() => {
                                arraymove(
                                    this.plugin.settings.folder_templates,
                                    index,
                                    index - 1
                                );
                                this.plugin.save_settings();
                                this.display();
                            });
                    })
                    .addExtraButton((cb) => {
                        cb.setIcon("down-chevron-glyph")
                            .setTooltip("Move down")
                            .onClick(() => {
                                arraymove(
                                    this.plugin.settings.folder_templates,
                                    index,
                                    index + 1
                                );
                                this.plugin.save_settings();
                                this.display();
                            });
                    })
                    .addExtraButton((cb) => {
                        cb.setIcon("cross")
                            .setTooltip("Delete")
                            .onClick(() => {
                                this.plugin.settings.folder_templates.splice(
                                    index,
                                    1
                                );
                                this.plugin.save_settings();
                                this.display();
                            });
                    });
                s.infoEl.remove();
            }
        );
    }
Example #29
Source File: settings.ts    From obsidian-initiative-tracker with GNU General Public License v3.0 4 votes vote down vote up
private _displayPlayers(additionalContainer: HTMLDetailsElement) {
        additionalContainer.empty();
        additionalContainer.ontoggle = () => {
            this.plugin.data.openState.player = additionalContainer.open;
        };
        const summary = additionalContainer.createEl("summary");
        new Setting(summary).setHeading().setName("Players");
        summary.createDiv("collapser").createDiv("handle");
        new Setting(additionalContainer)
            .setName("Add New Player")
            .setDesc(
                "Players added here will be available to add to a party. If you do not have a party created, all players will be added to a new encounter."
            )
            .addButton((button: ButtonComponent): ButtonComponent => {
                let b = button
                    .setTooltip("Add Player")
                    .setButtonText("+")
                    .onClick(async () => {
                        const modal = new NewPlayerModal(this.plugin);
                        modal.open();
                        modal.onClose = async () => {
                            if (!modal.saved) return;

                            await this.plugin.savePlayer({
                                ...modal.player,
                                player: true
                            });

                            this._displayPlayers(additionalContainer);
                        };
                    });

                return b;
            });
        const additional = additionalContainer.createDiv("additional");
        const playerView = additional.createDiv("initiative-tracker-players");
        if (!this.plugin.data.players.length) {
            additional
                .createDiv({
                    attr: {
                        style: "display: flex; justify-content: center; padding-bottom: 18px;"
                    }
                })
                .createSpan({
                    text: "No saved players! Create one to see it here."
                });
        } else {
            const headers = playerView.createDiv(
                "initiative-tracker-player headers"
            );

            headers.createDiv({ text: "Name" });
            new ExtraButtonComponent(headers.createDiv())
                .setIcon(HP)
                .setTooltip("Max HP");
            new ExtraButtonComponent(headers.createDiv())
                .setIcon(AC)
                .setTooltip("Armor Class");
            new ExtraButtonComponent(headers.createDiv())
                .setIcon(INITIATIVE)
                .setTooltip("Initiative Modifier");

            headers.createDiv();

            for (let player of this.plugin.data.players) {
                const playerDiv = playerView.createDiv(
                    "initiative-tracker-player"
                );
                playerDiv.createDiv({ text: player.name });
                playerDiv.createDiv({
                    text: `${player.hp ?? DEFAULT_UNDEFINED}`
                });
                playerDiv.createDiv({
                    text: `${player.ac ?? DEFAULT_UNDEFINED}`
                });
                playerDiv.createDiv({
                    text: `${player.modifier ?? DEFAULT_UNDEFINED}`
                });
                const icons = playerDiv.createDiv(
                    "initiative-tracker-player-icon"
                );
                new ExtraButtonComponent(icons.createDiv())
                    .setIcon("pencil")
                    .setTooltip("Edit")
                    .onClick(() => {
                        const modal = new NewPlayerModal(this.plugin, player);
                        modal.open();
                        modal.onClose = async () => {
                            if (!modal.saved) return;
                            await this.plugin.updatePlayer(
                                player,
                                modal.player
                            );
                            this.plugin.app.workspace.trigger(
                                "initiative-tracker:creature-updated-in-settings",
                                player
                            );

                            this._displayPlayers(additionalContainer);
                        };
                    });
                new ExtraButtonComponent(icons.createDiv())
                    .setIcon("trash")
                    .setTooltip("Delete")
                    .onClick(async () => {
                        this.plugin.data.players =
                            this.plugin.data.players.filter((p) => p != player);

                        await this.plugin.saveSettings();
                        this._displayPlayers(additionalContainer);
                    });
            }
        }
    }