refactor(interaction): reduce cognitive complexity and centralize color constants
SonarQube Scan / SonarQube Trigger (push) Successful in 3m49s

This commit is contained in:
2026-01-27 13:43:18 +07:00
parent 7f4f448b47
commit d167508a55
4 changed files with 335 additions and 241 deletions
+20 -17
View File
@@ -10,34 +10,37 @@ import (
"github.com/charmbracelet/lipgloss"
)
func (m *model) handleCommandSelection(item commandItem) (tea.Model, tea.Cmd) {
switch item.name {
case "slug":
m.showingCommands = false
m.editingSlug = true
m.slugInput.SetValue(m.interaction.slug.String())
m.slugInput.Focus()
return m, tea.Batch(tea.ClearScreen, textinput.Blink)
case "tunnel-type":
m.showingCommands = false
m.showingComingSoon = true
return m, tea.Batch(tickCmd(5*time.Second), tea.ClearScreen, textinput.Blink)
default:
m.showingCommands = false
return m, nil
}
}
func (m *model) commandsUpdate(msg tea.KeyMsg) (tea.Model, tea.Cmd) {
var cmd tea.Cmd
switch {
case key.Matches(msg, m.keymap.quit):
case key.Matches(msg, m.keymap.quit), msg.String() == "esc":
m.showingCommands = false
return m, tea.Batch(tea.ClearScreen, textinput.Blink)
case msg.String() == "enter":
selectedItem := m.commandList.SelectedItem()
if selectedItem != nil {
item := selectedItem.(commandItem)
if item.name == "slug" {
m.showingCommands = false
m.editingSlug = true
m.slugInput.SetValue(m.interaction.slug.String())
m.slugInput.Focus()
return m, tea.Batch(tea.ClearScreen, textinput.Blink)
} else if item.name == "tunnel-type" {
m.showingCommands = false
m.showingComingSoon = true
return m, tea.Batch(tickCmd(5*time.Second), tea.ClearScreen, textinput.Blink)
}
m.showingCommands = false
return m, nil
return m.handleCommandSelection(item)
}
case msg.String() == "esc":
m.showingCommands = false
return m, tea.Batch(tea.ClearScreen, textinput.Blink)
}
m.commandList, cmd = m.commandList.Update(msg)
return m, cmd
+140 -110
View File
@@ -23,164 +23,194 @@ func (m *model) dashboardUpdate(msg tea.KeyMsg) (tea.Model, tea.Cmd) {
}
func (m *model) dashboardView() string {
titleStyle := lipgloss.NewStyle().
Bold(true).
Foreground(lipgloss.Color("#7D56F4")).
PaddingTop(1)
subtitleStyle := lipgloss.NewStyle().
Foreground(lipgloss.Color("#888888")).
Italic(true)
urlStyle := lipgloss.NewStyle().
Foreground(lipgloss.Color("#7D56F4")).
Underline(true).
Italic(true)
urlBoxStyle := lipgloss.NewStyle().
Foreground(lipgloss.Color("#04B575")).
Bold(true).
Italic(true)
keyHintStyle := lipgloss.NewStyle().
Foreground(lipgloss.Color("#7D56F4")).
Bold(true)
isCompact := shouldUseCompactLayout(m.width, BreakpointLarge)
var b strings.Builder
b.WriteString(m.renderHeader(isCompact))
b.WriteString(m.renderUserInfo(isCompact))
b.WriteString(m.renderQuickActions(isCompact))
b.WriteString(m.renderFooter(isCompact))
isCompact := shouldUseCompactLayout(m.width, 85)
return b.String()
}
var asciiArtMargin int
if isCompact {
asciiArtMargin = 0
} else {
asciiArtMargin = 1
}
func (m *model) renderHeader(isCompact bool) string {
var b strings.Builder
asciiArtMargin := getMarginValue(isCompact, 0, 1)
asciiArtStyle := lipgloss.NewStyle().
Bold(true).
Foreground(lipgloss.Color("#7D56F4")).
Foreground(lipgloss.Color(ColorPrimary)).
MarginBottom(asciiArtMargin)
var asciiArt string
if shouldUseCompactLayout(m.width, 50) {
asciiArt = "TUNNEL PLS"
} else if isCompact {
asciiArt = `
b.WriteString(asciiArtStyle.Render(m.getASCIIArt()))
b.WriteString("\n")
if !shouldUseCompactLayout(m.width, BreakpointSmall) {
b.WriteString(m.renderSubtitle())
} else {
b.WriteString("\n")
}
return b.String()
}
func (m *model) getASCIIArt() string {
if shouldUseCompactLayout(m.width, BreakpointTiny) {
return "TUNNEL PLS"
}
if shouldUseCompactLayout(m.width, BreakpointLarge) {
return `
▀█▀ █ █ █▄ █ █▄ █ ██▀ █ ▄▀▀ █ ▄▀▀
█ ▀▄█ █ ▀█ █ ▀█ █▄▄ █▄▄ ▄█▀ █▄▄ ▄█▀`
} else {
asciiArt = `
}
return `
████████╗██╗ ██╗███╗ ██╗███╗ ██╗███████╗██╗ ██████╗ ██╗ ███████╗
╚══██╔══╝██║ ██║████╗ ██║████╗ ██║██╔════╝██║ ██╔══██╗██║ ██╔════╝
██║ ██║ ██║██╔██╗ ██║██╔██╗ ██║█████╗ ██║ ██████╔╝██║ ███████╗
██║ ██║ ██║██║╚██╗██║██║╚██╗██║██╔══╝ ██║ ██╔═══╝ ██║ ╚════██║
██║ ╚██████╔╝██║ ╚████║██║ ╚████║███████╗███████╗ ██║ ███████╗███████║
╚═╝ ╚═════╝ ╚═╝ ╚═══╝╚═╝ ╚═══╝╚══════╝╚══════╝ ╚═╝ ╚══════╝╚══════╝`
}
}
b.WriteString(asciiArtStyle.Render(asciiArt))
b.WriteString("\n")
func (m *model) renderSubtitle() string {
subtitleStyle := lipgloss.NewStyle().
Foreground(lipgloss.Color(ColorGray)).
Italic(true)
if !shouldUseCompactLayout(m.width, 60) {
b.WriteString(subtitleStyle.Render("Secure tunnel service by Bagas • "))
b.WriteString(urlStyle.Render("https://fossy.my.id"))
b.WriteString("\n\n")
} else {
b.WriteString("\n")
}
urlStyle := lipgloss.NewStyle().
Foreground(lipgloss.Color(ColorPrimary)).
Underline(true).
Italic(true)
return subtitleStyle.Render("Secure tunnel service by Bagas • ") +
urlStyle.Render("https://fossy.my.id") + "\n\n"
}
func (m *model) renderUserInfo(isCompact bool) string {
boxMaxWidth := getResponsiveWidth(m.width, 10, 40, 80)
var boxPadding int
var boxMargin int
if isCompact {
boxPadding = 1
boxMargin = 1
} else {
boxPadding = 2
boxMargin = 2
}
boxPadding := getMarginValue(isCompact, 1, 2)
boxMargin := getMarginValue(isCompact, 1, 2)
responsiveInfoBox := lipgloss.NewStyle().
Border(lipgloss.RoundedBorder()).
BorderForeground(lipgloss.Color("#7D56F4")).
BorderForeground(lipgloss.Color(ColorPrimary)).
Padding(1, boxPadding).
MarginTop(boxMargin).
MarginBottom(boxMargin).
Width(boxMaxWidth)
authenticatedUser := m.interaction.user
infoContent := m.getUserInfoContent(isCompact)
return responsiveInfoBox.Render(infoContent) + "\n"
}
func (m *model) getUserInfoContent(isCompact bool) string {
userInfoStyle := lipgloss.NewStyle().
Foreground(lipgloss.Color("#FAFAFA")).
Foreground(lipgloss.Color(ColorWhite)).
Bold(true)
sectionHeaderStyle := lipgloss.NewStyle().
Foreground(lipgloss.Color("#888888")).
Foreground(lipgloss.Color(ColorGray)).
Bold(true)
addressStyle := lipgloss.NewStyle().
Foreground(lipgloss.Color("#FAFAFA"))
Foreground(lipgloss.Color(ColorWhite))
var infoContent string
if shouldUseCompactLayout(m.width, 70) {
infoContent = fmt.Sprintf("👤 %s\n\n%s\n%s",
urlBoxStyle := lipgloss.NewStyle().
Foreground(lipgloss.Color(ColorSecondary)).
Bold(true).
Italic(true)
authenticatedUser := m.interaction.user
tunnelURL := urlBoxStyle.Render(m.getTunnelURL())
if isCompact {
return fmt.Sprintf("👤 %s\n\n%s\n%s",
userInfoStyle.Render(authenticatedUser),
sectionHeaderStyle.Render("🌐 FORWARDING ADDRESS:"),
addressStyle.Render(fmt.Sprintf(" %s", urlBoxStyle.Render(m.getTunnelURL()))))
} else {
infoContent = fmt.Sprintf("👤 Authenticated as: %s\n\n%s\n %s",
userInfoStyle.Render(authenticatedUser),
sectionHeaderStyle.Render("🌐 FORWARDING ADDRESS:"),
addressStyle.Render(urlBoxStyle.Render(m.getTunnelURL())))
addressStyle.Render(fmt.Sprintf(" %s", tunnelURL)))
}
b.WriteString(responsiveInfoBox.Render(infoContent))
return fmt.Sprintf("👤 Authenticated as: %s\n\n%s\n %s",
userInfoStyle.Render(authenticatedUser),
sectionHeaderStyle.Render("🌐 FORWARDING ADDRESS:"),
addressStyle.Render(tunnelURL))
}
func (m *model) renderQuickActions(isCompact bool) string {
var b strings.Builder
titleStyle := lipgloss.NewStyle().
Bold(true).
Foreground(lipgloss.Color(ColorPrimary)).
PaddingTop(1)
b.WriteString(titleStyle.Render(m.getQuickActionsTitle()))
b.WriteString("\n")
var quickActionsTitle string
if shouldUseCompactLayout(m.width, 50) {
quickActionsTitle = "Actions"
} else if isCompact {
quickActionsTitle = "Quick Actions"
} else {
quickActionsTitle = "✨ Quick Actions"
}
b.WriteString(titleStyle.Render(quickActionsTitle))
b.WriteString("\n")
var featureMargin int
if isCompact {
featureMargin = 1
} else {
featureMargin = 2
}
compactFeatureStyle := lipgloss.NewStyle().
Foreground(lipgloss.Color("#FAFAFA")).
featureMargin := getMarginValue(isCompact, 1, 2)
featureStyle := lipgloss.NewStyle().
Foreground(lipgloss.Color(ColorWhite)).
MarginLeft(featureMargin)
var commandsText string
var quitText string
if shouldUseCompactLayout(m.width, 60) {
commandsText = fmt.Sprintf(" %s Commands", keyHintStyle.Render("[C]"))
quitText = fmt.Sprintf(" %s Quit", keyHintStyle.Render("[Q]"))
} else {
commandsText = fmt.Sprintf(" %s Open commands menu", keyHintStyle.Render("[C]"))
quitText = fmt.Sprintf(" %s Quit application", keyHintStyle.Render("[Q]"))
}
keyHintStyle := lipgloss.NewStyle().
Foreground(lipgloss.Color(ColorPrimary)).
Bold(true)
b.WriteString(compactFeatureStyle.Render(commandsText))
commands := m.getActionCommands(keyHintStyle)
b.WriteString(featureStyle.Render(commands.commandsText))
b.WriteString("\n")
b.WriteString(compactFeatureStyle.Render(quitText))
if !shouldUseCompactLayout(m.width, 70) {
b.WriteString("\n\n")
footerStyle := lipgloss.NewStyle().
Foreground(lipgloss.Color("#666666")).
Italic(true)
b.WriteString(footerStyle.Render("Press 'C' to customize your tunnel settings"))
}
b.WriteString(featureStyle.Render(commands.quitText))
return b.String()
}
func (m *model) getQuickActionsTitle() string {
if shouldUseCompactLayout(m.width, BreakpointTiny) {
return "Actions"
}
if shouldUseCompactLayout(m.width, BreakpointLarge) {
return "Quick Actions"
}
return "✨ Quick Actions"
}
type actionCommands struct {
commandsText string
quitText string
}
func (m *model) getActionCommands(keyHintStyle lipgloss.Style) actionCommands {
if shouldUseCompactLayout(m.width, BreakpointSmall) {
return actionCommands{
commandsText: fmt.Sprintf(" %s Commands", keyHintStyle.Render("[C]")),
quitText: fmt.Sprintf(" %s Quit", keyHintStyle.Render("[Q]")),
}
}
return actionCommands{
commandsText: fmt.Sprintf(" %s Open commands menu", keyHintStyle.Render("[C]")),
quitText: fmt.Sprintf(" %s Quit application", keyHintStyle.Render("[Q]")),
}
}
func (m *model) renderFooter(isCompact bool) string {
if isCompact {
return ""
}
footerStyle := lipgloss.NewStyle().
Foreground(lipgloss.Color(ColorDarkGray)).
Italic(true)
return "\n\n" + footerStyle.Render("Press 'C' to customize your tunnel settings")
}
func getMarginValue(isCompact bool, compactValue, normalValue int) int {
if isCompact {
return compactValue
}
return normalValue
}
+19
View File
@@ -42,6 +42,25 @@ type model struct {
height int
}
const (
ColorPrimary = "#7D56F4"
ColorSecondary = "#04B575"
ColorGray = "#888888"
ColorDarkGray = "#666666"
ColorWhite = "#FAFAFA"
ColorError = "#FF0000"
ColorErrorBg = "#3D0000"
ColorWarning = "#FFA500"
ColorWarningBg = "#3D2000"
)
const (
BreakpointTiny = 50
BreakpointSmall = 60
BreakpointMedium = 70
BreakpointLarge = 85
)
func (m *model) getTunnelURL() string {
if m.tunnelType == types.TunnelTypeHTTP {
return buildURL(m.protocol, m.interaction.slug.String(), m.domain)
+156 -114
View File
@@ -21,7 +21,7 @@ func (m *model) slugUpdate(msg tea.KeyMsg) (tea.Model, tea.Cmd) {
}
switch msg.String() {
case "esc":
case "esc", "ctrl+c":
m.editingSlug = false
m.slugError = ""
return m, tea.Batch(tea.ClearScreen, textinput.Blink)
@@ -40,10 +40,6 @@ func (m *model) slugUpdate(msg tea.KeyMsg) (tea.Model, tea.Cmd) {
m.editingSlug = false
m.slugError = ""
return m, tea.Batch(tea.ClearScreen, textinput.Blink)
case "ctrl+c":
m.editingSlug = false
m.slugError = ""
return m, tea.Batch(tea.ClearScreen, textinput.Blink)
default:
if key.Matches(msg, m.keymap.random) {
newSubdomain, err := m.randomizer.String(20)
@@ -51,8 +47,6 @@ func (m *model) slugUpdate(msg tea.KeyMsg) (tea.Model, tea.Cmd) {
return m, cmd
}
m.slugInput.SetValue(newSubdomain)
m.slugError = ""
m.slugInput, cmd = m.slugInput.Update(msg)
}
m.slugError = ""
m.slugInput, cmd = m.slugInput.Update(msg)
@@ -61,163 +55,211 @@ func (m *model) slugUpdate(msg tea.KeyMsg) (tea.Model, tea.Cmd) {
}
func (m *model) slugView() string {
isCompact := shouldUseCompactLayout(m.width, 70)
isVeryCompact := shouldUseCompactLayout(m.width, 50)
isCompact := shouldUseCompactLayout(m.width, BreakpointMedium)
isVeryCompact := shouldUseCompactLayout(m.width, BreakpointTiny)
var boxPadding int
var boxMargin int
if isVeryCompact {
boxPadding = 1
boxMargin = 1
} else if isCompact {
boxPadding = 1
boxMargin = 1
} else {
boxPadding = 2
boxMargin = 2
var b strings.Builder
b.WriteString(m.renderSlugTitle(isVeryCompact))
if m.tunnelType != types.TunnelTypeHTTP {
b.WriteString(m.renderTCPWarning(isVeryCompact, isCompact))
return b.String()
}
b.WriteString(m.renderSlugRules(isVeryCompact, isCompact))
b.WriteString(m.renderSlugInstruction(isVeryCompact))
b.WriteString(m.renderSlugInput(isVeryCompact, isCompact))
b.WriteString(m.renderSlugPreview(isVeryCompact))
b.WriteString(m.renderSlugHelp(isVeryCompact))
return b.String()
}
func (m *model) renderSlugTitle(isVeryCompact bool) string {
titleStyle := lipgloss.NewStyle().
Bold(true).
Foreground(lipgloss.Color("#7D56F4")).
Foreground(lipgloss.Color(ColorPrimary)).
PaddingTop(1).
PaddingBottom(1)
instructionStyle := lipgloss.NewStyle().
Foreground(lipgloss.Color("#FAFAFA")).
MarginTop(1)
title := "🔧 Edit Subdomain"
if isVeryCompact {
title = "Edit Subdomain"
}
inputBoxStyle := lipgloss.NewStyle().
return titleStyle.Render(title) + "\n\n"
}
func (m *model) renderTCPWarning(isVeryCompact, isCompact bool) string {
boxPadding := getPaddingValue(isVeryCompact, isCompact)
boxMargin := getMarginValue(isCompact, 1, 2)
warningBoxWidth := getResponsiveWidth(m.width, 10, 30, 60)
warningBoxStyle := lipgloss.NewStyle().
Foreground(lipgloss.Color(ColorWarning)).
Background(lipgloss.Color(ColorWarningBg)).
Bold(true).
Border(lipgloss.RoundedBorder()).
BorderForeground(lipgloss.Color("#7D56F4")).
BorderForeground(lipgloss.Color(ColorWarning)).
Padding(1, boxPadding).
MarginTop(boxMargin).
MarginBottom(boxMargin)
MarginBottom(boxMargin).
Width(warningBoxWidth)
helpStyle := lipgloss.NewStyle().
Foreground(lipgloss.Color("#666666")).
Foreground(lipgloss.Color(ColorDarkGray)).
Italic(true).
MarginTop(1)
errorBoxStyle := lipgloss.NewStyle().
Foreground(lipgloss.Color("#FF0000")).
Background(lipgloss.Color("#3D0000")).
Bold(true).
Border(lipgloss.RoundedBorder()).
BorderForeground(lipgloss.Color("#FF0000")).
Padding(0, boxPadding).
MarginTop(1).
MarginBottom(1)
warningText := m.getTCPWarningText(isVeryCompact)
helpText := m.getTCPHelpText(isVeryCompact)
var b strings.Builder
b.WriteString(warningBoxStyle.Render(warningText))
b.WriteString("\n\n")
b.WriteString(helpStyle.Render(helpText))
return b.String()
}
func (m *model) getTCPWarningText(isVeryCompact bool) string {
if isVeryCompact {
return "⚠️ TCP tunnels don't support custom subdomains."
}
return "⚠️ TCP tunnels cannot have custom subdomains. Only HTTP/HTTPS tunnels support subdomain customization."
}
func (m *model) getTCPHelpText(isVeryCompact bool) string {
if isVeryCompact {
return "Press any key to go back"
}
return "Press Enter or Esc to go back"
}
func (m *model) renderSlugRules(isVeryCompact, isCompact bool) string {
boxPadding := getPaddingValue(isVeryCompact, isCompact)
rulesBoxWidth := getResponsiveWidth(m.width, 10, 30, 60)
rulesBoxStyle := lipgloss.NewStyle().
Foreground(lipgloss.Color("#FAFAFA")).
Foreground(lipgloss.Color(ColorWhite)).
Border(lipgloss.RoundedBorder()).
BorderForeground(lipgloss.Color("#7D56F4")).
BorderForeground(lipgloss.Color(ColorPrimary)).
Padding(0, boxPadding).
MarginTop(1).
MarginBottom(1).
Width(rulesBoxWidth)
var b strings.Builder
var title string
rulesContent := m.getRulesContent(isVeryCompact, isCompact)
return rulesBoxStyle.Render(rulesContent) + "\n"
}
func (m *model) getRulesContent(isVeryCompact, isCompact bool) string {
if isVeryCompact {
title = "Edit Subdomain"
} else {
title = "🔧 Edit Subdomain"
}
b.WriteString(titleStyle.Render(title))
b.WriteString("\n\n")
if m.tunnelType != types.TunnelTypeHTTP {
warningBoxWidth := getResponsiveWidth(m.width, 10, 30, 60)
warningBoxStyle := lipgloss.NewStyle().
Foreground(lipgloss.Color("#FFA500")).
Background(lipgloss.Color("#3D2000")).
Bold(true).
Border(lipgloss.RoundedBorder()).
BorderForeground(lipgloss.Color("#FFA500")).
Padding(1, boxPadding).
MarginTop(boxMargin).
MarginBottom(boxMargin).
Width(warningBoxWidth)
var warningText string
if isVeryCompact {
warningText = "⚠️ TCP tunnels don't support custom subdomains."
} else {
warningText = "⚠️ TCP tunnels cannot have custom subdomains. Only HTTP/HTTPS tunnels support subdomain customization."
}
b.WriteString(warningBoxStyle.Render(warningText))
b.WriteString("\n\n")
var helpText string
if isVeryCompact {
helpText = "Press any key to go back"
} else {
helpText = "Press Enter or Esc to go back"
}
b.WriteString(helpStyle.Render(helpText))
return b.String()
return "Rules:\n3-20 chars\na-z, 0-9, -\nNo leading/trailing -"
}
var rulesContent string
if isVeryCompact {
rulesContent = "Rules:\n3-20 chars\na-z, 0-9, -\nNo leading/trailing -"
} else if isCompact {
rulesContent = "📋 Rules:\n • 3-20 chars\n • a-z, 0-9, -\n • No leading/trailing -"
} else {
rulesContent = "📋 Rules: \n\t• 3-20 chars \n\t• a-z, 0-9, - \n\t• No leading/trailing -"
if isCompact {
return "📋 Rules:\n • 3-20 chars\n • a-z, 0-9, -\n • No leading/trailing -"
}
b.WriteString(rulesBoxStyle.Render(rulesContent))
b.WriteString("\n")
var instruction string
return "📋 Rules: \n\t• 3-20 chars \n\t• a-z, 0-9, - \n\t• No leading/trailing -"
}
func (m *model) renderSlugInstruction(isVeryCompact bool) string {
instructionStyle := lipgloss.NewStyle().
Foreground(lipgloss.Color(ColorWhite)).
MarginTop(1)
instruction := "Enter your custom subdomain:"
if isVeryCompact {
instruction = "Custom subdomain:"
} else {
instruction = "Enter your custom subdomain:"
}
b.WriteString(instructionStyle.Render(instruction))
b.WriteString("\n")
return instructionStyle.Render(instruction) + "\n"
}
func (m *model) renderSlugInput(isVeryCompact, isCompact bool) string {
boxPadding := getPaddingValue(isVeryCompact, isCompact)
boxMargin := getMarginValue(isCompact, 1, 2)
if m.slugError != "" {
errorInputBoxStyle := lipgloss.NewStyle().
Border(lipgloss.RoundedBorder()).
BorderForeground(lipgloss.Color("#FF0000")).
Padding(1, boxPadding).
MarginTop(boxMargin).
MarginBottom(1)
b.WriteString(errorInputBoxStyle.Render(m.slugInput.View()))
b.WriteString("\n")
b.WriteString(errorBoxStyle.Render("❌ " + m.slugError))
b.WriteString("\n")
} else {
b.WriteString(inputBoxStyle.Render(m.slugInput.View()))
b.WriteString("\n")
return m.renderErrorInput(boxPadding, boxMargin)
}
return m.renderNormalInput(boxPadding, boxMargin)
}
func (m *model) renderErrorInput(boxPadding, boxMargin int) string {
errorInputBoxStyle := lipgloss.NewStyle().
Border(lipgloss.RoundedBorder()).
BorderForeground(lipgloss.Color(ColorError)).
Padding(1, boxPadding).
MarginTop(boxMargin).
MarginBottom(1)
errorBoxStyle := lipgloss.NewStyle().
Foreground(lipgloss.Color(ColorError)).
Background(lipgloss.Color(ColorErrorBg)).
Bold(true).
Border(lipgloss.RoundedBorder()).
BorderForeground(lipgloss.Color(ColorError)).
Padding(0, boxPadding).
MarginTop(1).
MarginBottom(1)
var b strings.Builder
b.WriteString(errorInputBoxStyle.Render(m.slugInput.View()))
b.WriteString("\n")
b.WriteString(errorBoxStyle.Render("❌ " + m.slugError))
b.WriteString("\n")
return b.String()
}
func (m *model) renderNormalInput(boxPadding, boxMargin int) string {
inputBoxStyle := lipgloss.NewStyle().
Border(lipgloss.RoundedBorder()).
BorderForeground(lipgloss.Color(ColorPrimary)).
Padding(1, boxPadding).
MarginTop(boxMargin).
MarginBottom(boxMargin)
return inputBoxStyle.Render(m.slugInput.View()) + "\n"
}
func (m *model) renderSlugPreview(isVeryCompact bool) string {
previewURL := buildURL(m.protocol, m.slugInput.Value(), m.domain)
previewWidth := getResponsiveWidth(m.width, 10, 30, 80)
if len(previewURL) > previewWidth-10 {
if isVeryCompact {
previewURL = truncateString(previewURL, previewWidth-10)
}
previewStyle := lipgloss.NewStyle().
Foreground(lipgloss.Color("#04B575")).
Foreground(lipgloss.Color(ColorSecondary)).
Italic(true).
Width(previewWidth)
b.WriteString(previewStyle.Render(fmt.Sprintf("Preview: %s", previewURL)))
b.WriteString("\n")
var helpText string
return previewStyle.Render(fmt.Sprintf("Preview: %s", previewURL)) + "\n"
}
func (m *model) renderSlugHelp(isVeryCompact bool) string {
helpStyle := lipgloss.NewStyle().
Foreground(lipgloss.Color(ColorDarkGray)).
Italic(true).
MarginTop(1)
helpText := "Press Enter to save • CTRL+R for random • Esc to cancel"
if isVeryCompact {
helpText = "Enter: save • CTRL+R: random • Esc: cancel"
} else {
helpText = "Press Enter to save • CTRL+R for random • Esc to cancel"
}
b.WriteString(helpStyle.Render(helpText))
return b.String()
return helpStyle.Render(helpText)
}
func getPaddingValue(isVeryCompact, isCompact bool) int {
if isVeryCompact || isCompact {
return 1
}
return 2
}