ssh-portfolio/main.go
2026-04-14 11:23:48 +02:00

251 lines
5.0 KiB
Go
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

package main
import (
"fmt"
"strings"
"log"
tea "github.com/charmbracelet/bubbletea"
"github.com/charmbracelet/lipgloss"
"github.com/charmbracelet/ssh"
"github.com/charmbracelet/wish"
wishtea "github.com/charmbracelet/wish/bubbletea"
)
var asciiArt = []string{}
type model struct {
title string
sections []string
selected int
currentScreen string
width int
height int
mouseX int
mouseY int
mouseActive bool
isClicked bool
}
func initialModel() model {
return model{
title: "Đorđe Kšan",
sections: []string{"About", "Projects", "Contact"},
currentScreen: "menu",
mouseActive: true,
}
}
func (m model) Init() tea.Cmd {
return nil
}
func (m model) Update(msg tea.Msg) (tea.Model, tea.Cmd) {
switch msg := msg.(type) {
case tea.WindowSizeMsg:
m.width = msg.Width
m.height = msg.Height
if m.mouseX < 0 || m.mouseX > m.width || m.mouseY < 0 || m.mouseY > m.height {
m.mouseActive = false
}
case tea.KeyMsg:
switch msg.String() {
case "q", "ctrl+c":
return m, tea.Quit
case "up", "k":
if m.selected > 0 {
m.selected--
fmt.Println("up")
}
case "down", "j":
if m.selected < len(m.sections)-1 {
m.selected++
fmt.Println("down")
}
case "enter":
m.currentScreen = m.sections[m.selected]
return m, nil
case "left", "h":
case "right", "l":
case "b", "u", "backspace", "esc":
m.currentScreen = "menu"
return m, nil
default:
fmt.Println("click")
}
//TODO add mouse logic
case tea.MouseMsg:
m.mouseX = msg.X
m.mouseY = msg.Y
m.mouseActive = m.mouseX >= 0 && m.mouseX < m.width && m.mouseY >= 0 && m.mouseY < m.height
if msg.Button == tea.MouseButtonLeft && msg.Type == tea.MouseEventType(tea.MouseActionRelease) {
fmt.Println("mouse click")
}
return m, nil
}
return m, nil
}
func (m model) View() string {
titleStyle := lipgloss.NewStyle().
Bold(true).
Foreground(lipgloss.Color("#E2E8F0")).
Background(lipgloss.Color("#0F172A")).
Padding(0, 3)
sectionStyle := lipgloss.NewStyle().
Foreground(lipgloss.Color("#94A3B8"))
selectedSectionStyle := lipgloss.NewStyle().
Foreground(lipgloss.Color("#8A1D7D")).
Bold(true)
footerStyle := lipgloss.NewStyle().
Foreground(lipgloss.Color("#64748B"))
var output string
if m.currentScreen == "menu" {
output = titleStyle.Render(m.title) + "\n\n"
output += "Sections:\n"
for i, section := range m.sections {
if i == m.selected {
output += selectedSectionStyle.Render("- "+section) + "\n"
} else {
output += sectionStyle.Render("- "+section) + "\n"
}
}
output += "\n" + footerStyle.Render("Press q to quit.") + "\n"
} else {
switch m.currentScreen {
case "About":
output = m.renderAbout()
case "Projects":
output = m.renderProjects()
case "Contact":
output = m.renderContact()
}
}
return lipgloss.Place(
m.width,
m.height,
lipgloss.Center,
lipgloss.Center,
output,
)
}
var aboutText = `
Tbh I don't even know anymore. <3
`
var contactText = `
Get in touch with me at djordje@ksan.dev.
`
var projectsText = `
Here are some projects Ive worked on...
`
var (
titleStyle = lipgloss.NewStyle().
Bold(true).
Foreground(lipgloss.Color("#E2E8F0")).
Background(lipgloss.Color("#0F172A")).
Padding(0, 3)
sectionStyle = lipgloss.NewStyle().
Foreground(lipgloss.Color("#94A3B8"))
selectedSectionStyle = lipgloss.NewStyle().
Foreground(lipgloss.Color("#8A1D7D")).
Bold(true)
footerStyle = lipgloss.NewStyle().
Foreground(lipgloss.Color("#64748B"))
contentStyle = lipgloss.NewStyle().
Foreground(lipgloss.Color("#FFFFFF"))
)
func (m model) renderAbout() string {
var str strings.Builder
str.WriteString(titleStyle.Render("━━━ About Me ━━━"))
str.WriteString("\n")
str.WriteString(contentStyle.Render(aboutText))
str.WriteString("\n")
str.WriteString(footerStyle.Render("esc: back to menu"))
return str.String()
}
func (m model) renderProjects() string {
var str strings.Builder
str.WriteString(titleStyle.Render("━━━ Projects ━━━"))
str.WriteString("\n")
str.WriteString(contentStyle.Render(projectsText))
str.WriteString("\n")
str.WriteString(footerStyle.Render("esc: back to menu"))
return str.String()
}
func (m model) renderContact() string {
var str strings.Builder
str.WriteString(titleStyle.Render("━━━ Contact ━━━"))
str.WriteString("\n")
str.WriteString(contentStyle.Render(contactText))
str.WriteString("\n")
str.WriteString(footerStyle.Render("esc: back to menu"))
return str.String()
}
func main() {
server, _ := wish.NewServer(
wish.WithAddress("0.0.0.0:2222"),
wish.WithHostKeyPath(".ssh/host_ed25519"),
wish.WithMiddleware(wishtea.Middleware(teaHandler)),
)
_ = server.ListenAndServe()
}
func teaHandler(s ssh.Session) (tea.Model, []tea.ProgramOption) {
ip := s.RemoteAddr().String()
user := s.User()
println("New connection:")
log.Println("User:", user, "IP:", ip)
return initialModel(), []tea.ProgramOption{
tea.WithAltScreen(),
tea.WithMouseCellMotion(),
}
}