~ghost08/j5l

69d4e44a2ece83f85cc1d11cb8e9f4b608f747ae — VladimĂ­r Magyar a month ago d43f054
feat: viewport
3 files changed, 41 insertions(+), 20 deletions(-)

M delegate.go
M list.go
M main_model.go
M delegate.go => delegate.go +7 -9
@@ 32,8 32,6 @@ func (i *item) Title() string {
	return sb.String()
}

func (i *item) Description() string { return strings.ReplaceAll(i.je.Description, "\\", "\n") }

func (i *item) FilterValue() string { return i.je.Description }

func newItemDelegate(c *journal.Client, keys *delegateKeyMap) list.DefaultDelegate {


@@ 52,7 50,7 @@ func newItemDelegate(c *journal.Client, keys *delegateKeyMap) list.DefaultDelega
		case tea.KeyMsg:
			switch {
			case key.Matches(msg, keys.choose):
				return edit(c, itm.je)
				return edit(c, itm)
			case key.Matches(msg, keys.remove):
				if err := remove(c, itm.je.UID); err != nil {
					return func() tea.Msg { return err }


@@ 120,13 118,13 @@ func newDelegateKeyMap() *delegateKeyMap {
	}
}

func edit(c *journal.Client, je *journal.Entry) tea.Cmd {
func edit(c *journal.Client, itm *item) tea.Cmd {
	f, err := os.CreateTemp("", "j5l-")
	if err != nil {
		return func() tea.Msg { return fmt.Errorf("creating temp file: %w", err) }
	}
	if je != nil && je.Description != "" {
		if _, err := f.WriteString(je.UnescapedDescription()); err != nil {
	if itm != nil && itm.je.Description != "" {
		if _, err := f.WriteString(itm.je.UnescapedDescription()); err != nil {
			return func() tea.Msg { return fmt.Errorf("writing to temp file: %w", err) }
		}
	}


@@ 147,14 145,14 @@ func edit(c *journal.Client, je *journal.Entry) tea.Cmd {
		if err := os.Remove(f.Name()); err != nil {
			return func() tea.Msg { return err }
		}
		if je == nil {
		if itm == nil {
			err := create(c, string(data))
			if err != nil {
				return func() tea.Msg { return err }
			}
		} else {
			je.Description = string(data)
			err := update(c, je)
			itm.je.Description = string(data)
			err := update(c, itm.je)
			if err != nil {
				panic(err)
			}

M list.go => list.go +31 -6
@@ 4,6 4,7 @@ import (
	"git.sr.ht/~ghost08/j5l/journal"
	"github.com/charmbracelet/bubbles/key"
	"github.com/charmbracelet/bubbles/list"
	"github.com/charmbracelet/bubbles/viewport"
	tea "github.com/charmbracelet/bubbletea"
	"github.com/charmbracelet/lipgloss"
)


@@ 13,6 14,9 @@ var (
			Foreground(lipgloss.Color("#FFFDF5")).
			Background(lipgloss.Color("#25A065")).
			Padding(0, 1)
	viewportStyle = lipgloss.NewStyle().
			Foreground(lipgloss.Color("#35FDF5")).
			Border(lipgloss.RoundedBorder())

	statusMessageStyle = lipgloss.NewStyle().
				Foreground(lipgloss.AdaptiveColor{Light: "#04B575", Dark: "#04B575"}).


@@ 24,6 28,7 @@ type ListModel struct {
	list         list.Model
	keys         *listKeyMap
	delegateKeys *delegateKeyMap
	viewport     viewport.Model
}

func NewListModel() ListModel {


@@ 40,10 45,11 @@ func (m ListModel) setItems(js []*journal.Entry) (tea.Model, tea.Cmd) {
		items[i] = &item{je: j}
	}
	delegate := newItemDelegate(m.jc, delegateKeys)
	l := list.New(items, delegate, 0, 0)
	l.Title = "Journal entries"
	l.Styles.Title = titleStyle
	l.AdditionalFullHelpKeys = func() []key.Binding {
	m.list.SetItems(items)
	m.list.SetDelegate(delegate)
	m.list.Title = "Journal entries"
	m.list.Styles.Title = titleStyle
	m.list.AdditionalFullHelpKeys = func() []key.Binding {
		return []key.Binding{
			listKeys.insertItem,
			listKeys.toggleTitleBar,


@@ 52,11 58,18 @@ func (m ListModel) setItems(js []*journal.Entry) (tea.Model, tea.Cmd) {
			listKeys.toggleHelpMenu,
		}
	}
	m.list = l
	m.keys = listKeys
	m.viewport = viewport.New(100, 30)
	m.viewport.Style = lipgloss.NewStyle().Padding(2)
	return m, nil
}

func (m *ListModel) SetSize(width, height int) {
	m.list.SetSize(width/2, height)
	m.viewport.Width = (width / 2) - 1
	m.viewport.Height = height - 1
}

func (m ListModel) Init() tea.Cmd {
	return nil
}


@@ 83,6 96,10 @@ func (m ListModel) Update(msg tea.Msg) (tea.Model, tea.Cmd) {
	m.list = newListModel
	cmds = append(cmds, cmd)

	newViewportModel, cmd := m.viewport.Update(msg)
	m.viewport = newViewportModel
	cmds = append(cmds, cmd)

	return m, tea.Batch(cmds...)
}



@@ 114,7 131,15 @@ func (m ListModel) keyMatcher(msg tea.KeyMsg) (tea.Model, tea.Cmd) {
}

func (m ListModel) View() string {
	return m.list.View()
	if len(m.list.Items()) > 0 {
		itm := m.list.Items()[m.list.Index()]
		m.viewport.SetContent(itm.(*item).je.UnescapedDescription())
	}
	return lipgloss.JoinHorizontal(
		lipgloss.Top,
		m.list.View(),
		viewportStyle.Render(m.viewport.View()),
	)
}

type listKeyMap struct {

M main_model.go => main_model.go +3 -5
@@ 20,7 20,6 @@ const (
type MainModel struct {
	state State
	cs    journal.Settings
	ws    tea.WindowSizeMsg

	loadingModel LoadingModel
	listModel    ListModel


@@ 44,9 43,11 @@ func (m MainModel) Init() tea.Cmd {
func (m MainModel) Update(msg tea.Msg) (tea.Model, tea.Cmd) {
	switch msg := msg.(type) {
	case tea.WindowSizeMsg:
		m.ws = msg
		h, v := appStyle.GetFrameSize()
		m.listModel.SetSize(msg.Width-h, msg.Height-v)
	case []*journal.Entry:
		m.state = StateList
		m.listModel.jc = m.loadingModel.jc
	}
	switch m.state {
	case StateLoading:


@@ 55,9 56,6 @@ func (m MainModel) Update(msg tea.Msg) (tea.Model, tea.Cmd) {
		return m, cmd
	case StateList:
		// TODO this will be set every time
		h, v := appStyle.GetFrameSize()
		m.listModel.list.SetSize(m.ws.Width-h, m.ws.Height-v)
		m.listModel.jc = m.loadingModel.jc
		newModel, cmd := m.listModel.Update(msg)
		m.listModel = newModel.(ListModel)
		return m, cmd