From fd8506165e553949a2dcfb48803f756fe97baaf1 Mon Sep 17 00:00:00 2001 From: Christian Date: Sat, 2 Nov 2024 19:40:41 -0700 Subject: [PATCH] adding damage chart (#62) --- cmd/types.go | 165 +++++++++++++++++++++++++++++++++------------------ 1 file changed, 108 insertions(+), 57 deletions(-) diff --git a/cmd/types.go b/cmd/types.go index e5699ba..bdb0fa9 100644 --- a/cmd/types.go +++ b/cmd/types.go @@ -6,6 +6,7 @@ import ( "github.com/charmbracelet/bubbles/table" tea "github.com/charmbracelet/bubbletea" "github.com/charmbracelet/lipgloss" + "github.com/charmbracelet/x/term" "github.com/digitalghost-dev/poke-cli/connections" "golang.org/x/text/cases" "golang.org/x/text/language" @@ -26,8 +27,7 @@ func (m model) Update(msg tea.Msg) (tea.Model, tea.Cmd) { case tea.KeyMsg: switch msg.String() { case "q", "ctrl+c": - // Fully quiting the program while - // the table is in selection mode + // Quit the program when in selection mode m.selectedOption = "quit" return m, tea.Quit case "enter": @@ -51,30 +51,108 @@ func (m model) View() string { return "Select a type! Hit 'Q' or 'CTRL-C' to quit.\n" + typesTableBorder.Render(m.table.View()) + "\n" } -// Creating a separate function that handles all the logic for building the table. -func tableGeneration(endpoint string) table.Model { - columns := []table.Column{ - {Title: "Type", Width: 16}, +// Helper function to get color for a given type name from colorMap +func getTypeColor(typeName string) string { + color := colorMap[typeName] + + return color +} + +// Function to display type details after a type is selected +func displayTypeDetails(typesName string, endpoint string) { + + // Setting up variables to style the list + var columnWidth = 13 + var subtle = lipgloss.AdaptiveColor{Light: "#D9DCCF", Dark: "#383838"} + var list = lipgloss.NewStyle().Border(lipgloss.NormalBorder(), false, true, false, false).BorderForeground(subtle).MarginRight(2).Height(8).Width(columnWidth + 1) + var listHeader = lipgloss.NewStyle().BorderStyle(lipgloss.NormalBorder()).BorderBottom(true).BorderForeground(subtle).MarginRight(2).Render + var listItem = lipgloss.NewStyle().Render + var docStyle = lipgloss.NewStyle().Padding(1, 1, 1, 1) + + baseURL := "https://pokeapi.co/api/v2/" + typesStruct, typeName, _ := connections.TypesApiCall(endpoint, typesName, baseURL) + + // Format selected type + selectedType := cases.Title(language.English).String(typeName) + coloredType := lipgloss.NewStyle().Foreground(lipgloss.Color(getTypeColor(typeName))).Render(selectedType) + + fmt.Printf("You selected the %s type.\nNumber of Pokémon with type: %d\n", coloredType, len(typesStruct.Pokemon)) + fmt.Println("----------") + fmt.Println(styleBold.Render("Damage Chart:")) + + physicalWidth, _, _ := term.GetSize(uintptr(int(os.Stdout.Fd()))) + doc := strings.Builder{} + + // Helper function to build list items + buildListItems := func(items []struct{ Name, URL string }) string { + var itemList []string + for _, item := range items { + color := getTypeColor(item.Name) + coloredStyle := lipgloss.NewStyle().Foreground(lipgloss.Color(color)) + coloredItem := coloredStyle.Render(cases.Title(language.English).String(item.Name)) + itemList = append(itemList, listItem(coloredItem)) + } + return lipgloss.JoinVertical(lipgloss.Left, itemList...) } + // Render lists based on Damage Relations + lists := lipgloss.JoinHorizontal(lipgloss.Top, + list.Render( + lipgloss.JoinVertical(lipgloss.Left, + listHeader("Weakness"), + buildListItems([]struct{ Name, URL string }(typesStruct.DamageRelations.DoubleDamageFrom)), + ), + ), + list.Width(columnWidth).Render( + lipgloss.JoinVertical(lipgloss.Left, + listHeader("x2 Damage"), + buildListItems([]struct{ Name, URL string }(typesStruct.DamageRelations.DoubleDamageTo)), + ), + ), + list.Width(columnWidth).Render( + lipgloss.JoinVertical(lipgloss.Left, + listHeader("Resists"), + buildListItems([]struct{ Name, URL string }(typesStruct.DamageRelations.HalfDamageFrom)), + ), + ), + list.Width(columnWidth).Render( + lipgloss.JoinVertical(lipgloss.Left, + listHeader("x0.5 Damage"), + buildListItems([]struct{ Name, URL string }(typesStruct.DamageRelations.HalfDamageTo)), + ), + ), + list.Width(columnWidth).Render( + lipgloss.JoinVertical(lipgloss.Left, + listHeader("Immune"), + buildListItems([]struct{ Name, URL string }(typesStruct.DamageRelations.NoDamageFrom)), + ), + ), + list.Width(columnWidth).Render( + lipgloss.JoinVertical(lipgloss.Left, + listHeader("x0 Damage"), + buildListItems([]struct{ Name, URL string }(typesStruct.DamageRelations.NoDamageTo)), + ), + ), + ) + + // Append lists to document + doc.WriteString(lipgloss.JoinHorizontal(lipgloss.Top, lists)) + + if physicalWidth > 0 { + docStyle = docStyle.MaxWidth(physicalWidth) + } + + // Print the rendered document + fmt.Println(docStyle.Render(doc.String())) +} + +// Function that generates and handles the type selection table +func tableGeneration(endpoint string) table.Model { + columns := []table.Column{{Title: "Type", Width: 16}} rows := []table.Row{ - {"Normal"}, - {"Fire"}, - {"Water"}, - {"Electric"}, - {"Grass"}, - {"Ice"}, - {"Fighting"}, - {"Poison"}, - {"Ground"}, - {"Flying"}, - {"Psychic"}, - {"Bug"}, - {"Rock"}, - {"Ghost"}, - {"Dragon"}, - {"Steel"}, - {"Fairy"}, + {"Normal"}, {"Fire"}, {"Water"}, {"Electric"}, {"Grass"}, {"Ice"}, + {"Fighting"}, {"Poison"}, {"Ground"}, {"Flying"}, {"Psychic"}, {"Bug"}, + {"Rock"}, {"Ghost"}, {"Dragon"}, {"Steel"}, {"Fairy"}, } t := table.New( @@ -85,15 +163,8 @@ func tableGeneration(endpoint string) table.Model { ) s := table.DefaultStyles() - s.Header = s.Header. - BorderStyle(lipgloss.NormalBorder()). - BorderForeground(lipgloss.Color("#FFCC00")). - BorderBottom(true). - Bold(false) - s.Selected = s.Selected. - Foreground(lipgloss.Color("#000")). - Background(lipgloss.Color("#FFCC00")). - Bold(false) + s.Header = s.Header.BorderStyle(lipgloss.NormalBorder()).BorderForeground(lipgloss.Color("#FFCC00")).BorderBottom(true) + s.Selected = s.Selected.Foreground(lipgloss.Color("#000")).Background(lipgloss.Color("#FFCC00")) t.SetStyles(s) m := model{table: t} @@ -103,40 +174,22 @@ func tableGeneration(endpoint string) table.Model { os.Exit(1) } - // Type assert to model and access the selected option + // Access the selected option from the model finalModel, ok := programModel.(model) if !ok { fmt.Println("Error: could not retrieve final model") os.Exit(1) } - // Check if the user quit the program by pressing 'Q' or 'CTRL-C' - if finalModel.selectedOption == "quit" { - // Return early to prevent further execution - return t + if finalModel.selectedOption != "quit" { + typesName := strings.ToLower(finalModel.selectedOption) + displayTypeDetails(typesName, endpoint) // Call function to display type details } - // Proceed with the API call only if a type was selected - typesName := strings.ToLower(finalModel.selectedOption) - - baseURL := "https://pokeapi.co/api/v2/" - typeResponse, typeName, _ := connections.TypesApiCall(endpoint, typesName, baseURL) - - selectedType := cases.Title(language.English).String(typeName) - - pokemonCount := len(typeResponse.Pokemon) - - // Picking the type's color from the colorMap map in cmd/styles.go: - coloredStyle := lipgloss.NewStyle().Foreground(lipgloss.Color(colorMap[typeName])) - coloredType := coloredStyle.Render(selectedType) - - fmt.Printf("You selected Type: %s\nNumber of Pokémon with type: %d\n", coloredType, pokemonCount) return t } func TypesCommand() { - styleBold = lipgloss.NewStyle().Bold(true) - styleItalic = lipgloss.NewStyle().Italic(true) flag.Usage = func() { helpMessage := helpBorder.Render( @@ -153,13 +206,11 @@ func TypesCommand() { flag.Parse() - err := ValidateTypesArgs(os.Args) - if err != nil { + if err := ValidateTypesArgs(os.Args); err != nil { fmt.Println(err.Error()) os.Exit(1) } endpoint := strings.ToLower(os.Args[1])[0:4] - tableGeneration(endpoint) }