v0.33.1 9577fee

favorites_view.go RawHistoryFolder

1package systemviews
2
3import (
4	"fmt"
5	"strings"
6
7	"github.com/bnema/dumber/internal/domain/entity"
8)
9
10const defaultTagColor = "#808080"
11
12type favoritesRenderData struct {
13	Favorites      []*entity.Favorite
14	Tags           []*entity.Tag
15	TagFilter      *entity.TagID
16	UntaggedFilter bool
17	Notice         string
18	Error          string
19}
20
21func favoritesHTML(data favoritesRenderData) string {
22	return mustRenderComponent(FavoritesView(data))
23}
24
25func favoritesDocumentTitle(data favoritesRenderData) string {
26	count := len(data.Favorites)
27	if data.TagFilter != nil || data.UntaggedFilter {
28		if count == 1 {
29			return "Favorites — 1 filtered bookmark"
30		}
31		return fmt.Sprintf("Favorites — %d filtered bookmarks", count)
32	}
33	if count == 1 {
34		return "Favorites — 1 bookmark"
35	}
36	return fmt.Sprintf("Favorites — %d bookmarks", count)
37}
38
39func favoritesSummary(data favoritesRenderData) string {
40	return fmt.Sprintf("%d favorites · %d tags", len(data.Favorites), len(data.Tags))
41}
42
43func tagsSummary(data favoritesRenderData) string {
44	return fmt.Sprintf("%d tags", len(data.Tags))
45}
46
47func favoriteFilterClass(active bool) string {
48	classes := "sv-button sv-button-secondary"
49	if active {
50		classes += " sv-button-active"
51	}
52	return classes
53}
54
55func favoriteUntaggedFilterActive(data favoritesRenderData) bool {
56	return data.UntaggedFilter
57}
58
59func favoriteAllFilterActive(data favoritesRenderData) bool {
60	return data.TagFilter == nil && !data.UntaggedFilter
61}
62
63func favoriteTagFilterActive(data favoritesRenderData, tagID entity.TagID) bool {
64	return data.TagFilter != nil && *data.TagFilter == tagID
65}
66
67func favoriteItemLabel(favorite *entity.Favorite) string {
68	if favorite == nil {
69		return ""
70	}
71	label := strings.TrimSpace(favorite.Title)
72	if label == "" {
73		label = favorite.URL
74	}
75	return label
76}
77
78func favoriteMetaText(favorite *entity.Favorite) string {
79	if favorite == nil || favorite.ShortcutKey == nil {
80		return ""
81	}
82	return fmt.Sprintf("Shortcut %d", *favorite.ShortcutKey)
83}
84
85func favoriteTagButtonAction(favorite *entity.Favorite, tag *entity.Tag) string {
86	if favorite != nil && tag != nil && favorite.HasTag(tag.ID) {
87		return tagActionRemove
88	}
89	return tagActionAssign
90}
91
92func favoriteTagButtonLabel(favorite *entity.Favorite, tag *entity.Tag) string {
93	if tag == nil {
94		return ""
95	}
96	if favorite != nil && favorite.HasTag(tag.ID) {
97		return "✓ " + tag.Name
98	}
99	return "+ " + tag.Name
100}
101
102func favoriteTagButtonClass(favorite *entity.Favorite, tag *entity.Tag) string {
103	classes := "sv-button sv-button-secondary sv-tag-button"
104	if favorite != nil && tag != nil && favorite.HasTag(tag.ID) {
105		classes += " sv-button-active sv-tag-button-active"
106	}
107	return classes
108}
109
110func safeTagColor(raw string) string {
111	value := strings.TrimSpace(raw)
112	if len(value) != 4 && len(value) != 7 {
113		return defaultTagColor
114	}
115	if value[0] != '#' {
116		return defaultTagColor
117	}
118	for _, ch := range value[1:] {
119		if (ch >= '0' && ch <= '9') || (ch >= 'a' && ch <= 'f') || (ch >= 'A' && ch <= 'F') {
120			continue
121		}
122		return defaultTagColor
123	}
124	return value
125}
126
127func shortcutSelected(selected *int, value int) bool {
128	return selected != nil && *selected == value
129}
130
131func filterFavorites(favorites []*entity.Favorite, tagID *entity.TagID, untagged bool) []*entity.Favorite {
132	if tagID == nil && !untagged {
133		return favorites
134	}
135	out := make([]*entity.Favorite, 0, len(favorites))
136	for _, favorite := range favorites {
137		if favorite == nil {
138			continue
139		}
140		if untagged {
141			if len(favorite.Tags) != 0 {
142				continue
143			}
144		} else if tagID != nil && !favorite.HasTag(*tagID) {
145			continue
146		}
147		out = append(out, favorite)
148	}
149	return out
150}

Keyboard shortcuts

Single-key shortcuts are on. ctrl k and esc work whatever this says.

ctrl k :
go to a section, branch, tag, file or repository
?
this list
j k
move the row cursor down / up
enter
open the row under the cursor; on Files, a directory opens or closes in place
↑ ↓ ← → home end
in the file tree (focus on a row): previous / next row, close / open a directory or go to its parent / first entry, first / last row. They never open a file
l h
on Files: open a directory or a file / close a directory or go up to its parent, then to the parent page. Elsewhere: into the side panel (on a merge request, its files) / back to the content; there j k move between its controls
g g G
first / last row
/
filter the list; on Files, find a file anywhere in the repository (esc clears, enter opens the best match)
b
switch branch or tag
g s g f g c g b g m g i g r g a
tabs: summary, files, commits, branches & tags, merge requests, issues, releases, actions (when available)
g h
home
w
wide mode: use the whole width of the screen, or not (remembered)
y
copy a permalink pinned to the commit
d u x
diff: split / unified / collapse or expand all
e E
diff: the whole file in view / every file, with the lines the hunks hide
n
merge request: next note in the diff
esc
close a dialog, leave a field

Branches 8

Tags 42

↑↓ moveenter openesc close