fix(deps): update module github.com/caddyserver/certmagic to v0.25.1 - autoclosed #63

Closed
Renovate-Clanker wants to merge 113 commits from renovate/github.com-caddyserver-certmagic-0.x into main
4 changed files with 335 additions and 241 deletions
Showing only changes of commit a26d1672d9 - Show all commits
+20 -17
View File
@@ -10,34 +10,37 @@ import (
"github.com/charmbracelet/lipgloss" "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) { func (m *model) commandsUpdate(msg tea.KeyMsg) (tea.Model, tea.Cmd) {
var cmd tea.Cmd var cmd tea.Cmd
switch { switch {
case key.Matches(msg, m.keymap.quit): case key.Matches(msg, m.keymap.quit), msg.String() == "esc":
m.showingCommands = false m.showingCommands = false
return m, tea.Batch(tea.ClearScreen, textinput.Blink) return m, tea.Batch(tea.ClearScreen, textinput.Blink)
case msg.String() == "enter": case msg.String() == "enter":
selectedItem := m.commandList.SelectedItem() selectedItem := m.commandList.SelectedItem()
if selectedItem != nil { if selectedItem != nil {
item := selectedItem.(commandItem) item := selectedItem.(commandItem)
if item.name == "slug" { return m.handleCommandSelection(item)
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
}
case msg.String() == "esc":
m.showingCommands = false
return m, tea.Batch(tea.ClearScreen, textinput.Blink)
} }
m.commandList, cmd = m.commandList.Update(msg) m.commandList, cmd = m.commandList.Update(msg)
return m, cmd return m, cmd
+139 -109
View File
@@ -23,54 +23,50 @@ func (m *model) dashboardUpdate(msg tea.KeyMsg) (tea.Model, tea.Cmd) {
} }
func (m *model) dashboardView() string { func (m *model) dashboardView() string {
titleStyle := lipgloss.NewStyle(). isCompact := shouldUseCompactLayout(m.width, BreakpointLarge)
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)
var b strings.Builder 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(). asciiArtStyle := lipgloss.NewStyle().
Bold(true). Bold(true).
Foreground(lipgloss.Color("#7D56F4")). Foreground(lipgloss.Color(ColorPrimary)).
MarginBottom(asciiArtMargin) MarginBottom(asciiArtMargin)
var asciiArt string b.WriteString(asciiArtStyle.Render(m.getASCIIArt()))
if shouldUseCompactLayout(m.width, 50) { b.WriteString("\n")
asciiArt = "TUNNEL PLS"
} else if isCompact { if !shouldUseCompactLayout(m.width, BreakpointSmall) {
asciiArt = ` 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 `
████████╗██╗ ██╗███╗ ██╗███╗ ██╗███████╗██╗ ██████╗ ██╗ ███████╗ ████████╗██╗ ██╗███╗ ██╗███╗ ██╗███████╗██╗ ██████╗ ██╗ ███████╗
╚══██╔══╝██║ ██║████╗ ██║████╗ ██║██╔════╝██║ ██╔══██╗██║ ██╔════╝ ╚══██╔══╝██║ ██║████╗ ██║████╗ ██║██╔════╝██║ ██╔══██╗██║ ██╔════╝
██║ ██║ ██║██╔██╗ ██║██╔██╗ ██║█████╗ ██║ ██████╔╝██║ ███████╗ ██║ ██║ ██║██╔██╗ ██║██╔██╗ ██║█████╗ ██║ ██████╔╝██║ ███████╗
@@ -79,108 +75,142 @@ func (m *model) dashboardView() string {
╚═╝ ╚═════╝ ╚═╝ ╚═══╝╚═╝ ╚═══╝╚══════╝╚══════╝ ╚═╝ ╚══════╝╚══════╝` ╚═╝ ╚═════╝ ╚═╝ ╚═══╝╚═╝ ╚═══╝╚══════╝╚══════╝ ╚═╝ ╚══════╝╚══════╝`
} }
b.WriteString(asciiArtStyle.Render(asciiArt)) func (m *model) renderSubtitle() string {
b.WriteString("\n") subtitleStyle := lipgloss.NewStyle().
Foreground(lipgloss.Color(ColorGray)).
Italic(true)
if !shouldUseCompactLayout(m.width, 60) { urlStyle := lipgloss.NewStyle().
b.WriteString(subtitleStyle.Render("Secure tunnel service by Bagas • ")) Foreground(lipgloss.Color(ColorPrimary)).
b.WriteString(urlStyle.Render("https://fossy.my.id")) Underline(true).
b.WriteString("\n\n") Italic(true)
} else {
b.WriteString("\n") 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) boxMaxWidth := getResponsiveWidth(m.width, 10, 40, 80)
var boxPadding int boxPadding := getMarginValue(isCompact, 1, 2)
var boxMargin int boxMargin := getMarginValue(isCompact, 1, 2)
if isCompact {
boxPadding = 1
boxMargin = 1
} else {
boxPadding = 2
boxMargin = 2
}
responsiveInfoBox := lipgloss.NewStyle(). responsiveInfoBox := lipgloss.NewStyle().
Border(lipgloss.RoundedBorder()). Border(lipgloss.RoundedBorder()).
BorderForeground(lipgloss.Color("#7D56F4")). BorderForeground(lipgloss.Color(ColorPrimary)).
Padding(1, boxPadding). Padding(1, boxPadding).
MarginTop(boxMargin). MarginTop(boxMargin).
MarginBottom(boxMargin). MarginBottom(boxMargin).
Width(boxMaxWidth) 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(). userInfoStyle := lipgloss.NewStyle().
Foreground(lipgloss.Color("#FAFAFA")). Foreground(lipgloss.Color(ColorWhite)).
Bold(true) Bold(true)
sectionHeaderStyle := lipgloss.NewStyle(). sectionHeaderStyle := lipgloss.NewStyle().
Foreground(lipgloss.Color("#888888")). Foreground(lipgloss.Color(ColorGray)).
Bold(true) Bold(true)
addressStyle := lipgloss.NewStyle(). addressStyle := lipgloss.NewStyle().
Foreground(lipgloss.Color("#FAFAFA")) Foreground(lipgloss.Color(ColorWhite))
var infoContent string urlBoxStyle := lipgloss.NewStyle().
if shouldUseCompactLayout(m.width, 70) { Foreground(lipgloss.Color(ColorSecondary)).
infoContent = fmt.Sprintf("👤 %s\n\n%s\n%s", Bold(true).
userInfoStyle.Render(authenticatedUser), Italic(true)
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())))
}
b.WriteString(responsiveInfoBox.Render(infoContent)) authenticatedUser := m.interaction.user
b.WriteString("\n") tunnelURL := urlBoxStyle.Render(m.getTunnelURL())
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 { if isCompact {
featureMargin = 1 return fmt.Sprintf("👤 %s\n\n%s\n%s",
} else { userInfoStyle.Render(authenticatedUser),
featureMargin = 2 sectionHeaderStyle.Render("🌐 FORWARDING ADDRESS:"),
addressStyle.Render(fmt.Sprintf(" %s", tunnelURL)))
} }
compactFeatureStyle := lipgloss.NewStyle(). return fmt.Sprintf("👤 Authenticated as: %s\n\n%s\n %s",
Foreground(lipgloss.Color("#FAFAFA")). 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")
featureMargin := getMarginValue(isCompact, 1, 2)
featureStyle := lipgloss.NewStyle().
Foreground(lipgloss.Color(ColorWhite)).
MarginLeft(featureMargin) MarginLeft(featureMargin)
var commandsText string keyHintStyle := lipgloss.NewStyle().
var quitText string Foreground(lipgloss.Color(ColorPrimary)).
if shouldUseCompactLayout(m.width, 60) { Bold(true)
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]"))
}
b.WriteString(compactFeatureStyle.Render(commandsText)) commands := m.getActionCommands(keyHintStyle)
b.WriteString(featureStyle.Render(commands.commandsText))
b.WriteString("\n") b.WriteString("\n")
b.WriteString(compactFeatureStyle.Render(quitText)) b.WriteString(featureStyle.Render(commands.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"))
}
return b.String() 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 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 { func (m *model) getTunnelURL() string {
if m.tunnelType == types.TunnelTypeHTTP { if m.tunnelType == types.TunnelTypeHTTP {
return buildURL(m.protocol, m.interaction.slug.String(), m.domain) return buildURL(m.protocol, m.interaction.slug.String(), m.domain)
+148 -106
View File
@@ -21,7 +21,7 @@ func (m *model) slugUpdate(msg tea.KeyMsg) (tea.Model, tea.Cmd) {
} }
switch msg.String() { switch msg.String() {
case "esc": case "esc", "ctrl+c":
m.editingSlug = false m.editingSlug = false
m.slugError = "" m.slugError = ""
return m, tea.Batch(tea.ClearScreen, textinput.Blink) 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.editingSlug = false
m.slugError = "" m.slugError = ""
return m, tea.Batch(tea.ClearScreen, textinput.Blink) 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: default:
if key.Matches(msg, m.keymap.random) { if key.Matches(msg, m.keymap.random) {
newSubdomain, err := m.randomizer.String(20) newSubdomain, err := m.randomizer.String(20)
@@ -51,8 +47,6 @@ func (m *model) slugUpdate(msg tea.KeyMsg) (tea.Model, tea.Cmd) {
return m, cmd return m, cmd
} }
m.slugInput.SetValue(newSubdomain) m.slugInput.SetValue(newSubdomain)
m.slugError = ""
m.slugInput, cmd = m.slugInput.Update(msg)
} }
m.slugError = "" m.slugError = ""
m.slugInput, cmd = m.slugInput.Update(msg) 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 { func (m *model) slugView() string {
isCompact := shouldUseCompactLayout(m.width, 70) isCompact := shouldUseCompactLayout(m.width, BreakpointMedium)
isVeryCompact := shouldUseCompactLayout(m.width, 50) isVeryCompact := shouldUseCompactLayout(m.width, BreakpointTiny)
var boxPadding int var b strings.Builder
var boxMargin int b.WriteString(m.renderSlugTitle(isVeryCompact))
if isVeryCompact {
boxPadding = 1 if m.tunnelType != types.TunnelTypeHTTP {
boxMargin = 1 b.WriteString(m.renderTCPWarning(isVeryCompact, isCompact))
} else if isCompact { return b.String()
boxPadding = 1
boxMargin = 1
} else {
boxPadding = 2
boxMargin = 2
} }
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(). titleStyle := lipgloss.NewStyle().
Bold(true). Bold(true).
Foreground(lipgloss.Color("#7D56F4")). Foreground(lipgloss.Color(ColorPrimary)).
PaddingTop(1). PaddingTop(1).
PaddingBottom(1) PaddingBottom(1)
instructionStyle := lipgloss.NewStyle(). title := "🔧 Edit Subdomain"
Foreground(lipgloss.Color("#FAFAFA")).
MarginTop(1)
inputBoxStyle := lipgloss.NewStyle().
Border(lipgloss.RoundedBorder()).
BorderForeground(lipgloss.Color("#7D56F4")).
Padding(1, boxPadding).
MarginTop(boxMargin).
MarginBottom(boxMargin)
helpStyle := lipgloss.NewStyle().
Foreground(lipgloss.Color("#666666")).
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)
rulesBoxWidth := getResponsiveWidth(m.width, 10, 30, 60)
rulesBoxStyle := lipgloss.NewStyle().
Foreground(lipgloss.Color("#FAFAFA")).
Border(lipgloss.RoundedBorder()).
BorderForeground(lipgloss.Color("#7D56F4")).
Padding(0, boxPadding).
MarginTop(1).
MarginBottom(1).
Width(rulesBoxWidth)
var b strings.Builder
var title string
if isVeryCompact { if isVeryCompact {
title = "Edit Subdomain" title = "Edit Subdomain"
} else {
title = "🔧 Edit Subdomain"
} }
b.WriteString(titleStyle.Render(title))
b.WriteString("\n\n")
if m.tunnelType != types.TunnelTypeHTTP { 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) warningBoxWidth := getResponsiveWidth(m.width, 10, 30, 60)
warningBoxStyle := lipgloss.NewStyle(). warningBoxStyle := lipgloss.NewStyle().
Foreground(lipgloss.Color("#FFA500")). Foreground(lipgloss.Color(ColorWarning)).
Background(lipgloss.Color("#3D2000")). Background(lipgloss.Color(ColorWarningBg)).
Bold(true). Bold(true).
Border(lipgloss.RoundedBorder()). Border(lipgloss.RoundedBorder()).
BorderForeground(lipgloss.Color("#FFA500")). BorderForeground(lipgloss.Color(ColorWarning)).
Padding(1, boxPadding). Padding(1, boxPadding).
MarginTop(boxMargin). MarginTop(boxMargin).
MarginBottom(boxMargin). MarginBottom(boxMargin).
Width(warningBoxWidth) Width(warningBoxWidth)
var warningText string helpStyle := lipgloss.NewStyle().
if isVeryCompact { Foreground(lipgloss.Color(ColorDarkGray)).
warningText = "⚠️ TCP tunnels don't support custom subdomains." Italic(true).
} else { MarginTop(1)
warningText = "⚠️ TCP tunnels cannot have custom subdomains. Only HTTP/HTTPS tunnels support subdomain customization."
} warningText := m.getTCPWarningText(isVeryCompact)
helpText := m.getTCPHelpText(isVeryCompact)
var b strings.Builder
b.WriteString(warningBoxStyle.Render(warningText)) b.WriteString(warningBoxStyle.Render(warningText))
b.WriteString("\n\n") 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)) b.WriteString(helpStyle.Render(helpText))
return b.String() return b.String()
} }
var rulesContent string func (m *model) getTCPWarningText(isVeryCompact bool) string {
if isVeryCompact { if isVeryCompact {
rulesContent = "Rules:\n3-20 chars\na-z, 0-9, -\nNo leading/trailing -" return "⚠️ TCP tunnels don't support custom subdomains."
} else if isCompact { }
rulesContent = "📋 Rules:\n • 3-20 chars\n • a-z, 0-9, -\n • No leading/trailing -" return "⚠️ TCP tunnels cannot have custom subdomains. Only HTTP/HTTPS tunnels support subdomain customization."
} else {
rulesContent = "📋 Rules: \n\t• 3-20 chars \n\t• a-z, 0-9, - \n\t• No leading/trailing -"
} }
b.WriteString(rulesBoxStyle.Render(rulesContent))
b.WriteString("\n")
var instruction string 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(ColorWhite)).
Border(lipgloss.RoundedBorder()).
BorderForeground(lipgloss.Color(ColorPrimary)).
Padding(0, boxPadding).
MarginTop(1).
MarginBottom(1).
Width(rulesBoxWidth)
rulesContent := m.getRulesContent(isVeryCompact, isCompact)
return rulesBoxStyle.Render(rulesContent) + "\n"
}
func (m *model) getRulesContent(isVeryCompact, isCompact bool) string {
if isVeryCompact {
return "Rules:\n3-20 chars\na-z, 0-9, -\nNo leading/trailing -"
}
if isCompact {
return "📋 Rules:\n • 3-20 chars\n • a-z, 0-9, -\n • No leading/trailing -"
}
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 { if isVeryCompact {
instruction = "Custom subdomain:" 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 != "" { if m.slugError != "" {
return m.renderErrorInput(boxPadding, boxMargin)
}
return m.renderNormalInput(boxPadding, boxMargin)
}
func (m *model) renderErrorInput(boxPadding, boxMargin int) string {
errorInputBoxStyle := lipgloss.NewStyle(). errorInputBoxStyle := lipgloss.NewStyle().
Border(lipgloss.RoundedBorder()). Border(lipgloss.RoundedBorder()).
BorderForeground(lipgloss.Color("#FF0000")). BorderForeground(lipgloss.Color(ColorError)).
Padding(1, boxPadding). Padding(1, boxPadding).
MarginTop(boxMargin). MarginTop(boxMargin).
MarginBottom(1) 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(errorInputBoxStyle.Render(m.slugInput.View()))
b.WriteString("\n") b.WriteString("\n")
b.WriteString(errorBoxStyle.Render("❌ " + m.slugError)) b.WriteString(errorBoxStyle.Render("❌ " + m.slugError))
b.WriteString("\n") b.WriteString("\n")
} else {
b.WriteString(inputBoxStyle.Render(m.slugInput.View())) return b.String()
b.WriteString("\n")
} }
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) previewURL := buildURL(m.protocol, m.slugInput.Value(), m.domain)
previewWidth := getResponsiveWidth(m.width, 10, 30, 80) previewWidth := getResponsiveWidth(m.width, 10, 30, 80)
if len(previewURL) > previewWidth-10 { if isVeryCompact {
previewURL = truncateString(previewURL, previewWidth-10) previewURL = truncateString(previewURL, previewWidth-10)
} }
previewStyle := lipgloss.NewStyle(). previewStyle := lipgloss.NewStyle().
Foreground(lipgloss.Color("#04B575")). Foreground(lipgloss.Color(ColorSecondary)).
Italic(true). Italic(true).
Width(previewWidth) 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 { if isVeryCompact {
helpText = "Enter: save • CTRL+R: random • Esc: cancel" 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
} }