v0.23.2 bfd5eb4

favorite.go RawHistoryFolder

1package entity
2
3import "time"
4
5// FavoriteID uniquely identifies a favorite/bookmark.
6type FavoriteID int64
7
8// FolderID uniquely identifies a bookmark folder.
9type FolderID int64
10
11// TagID uniquely identifies a tag.
12type TagID int64
13
14// Favorite represents a bookmarked URL.
15type Favorite struct {
16	ID          FavoriteID `json:"id"`
17	URL         string     `json:"url"`
18	Title       string     `json:"title"`
19	FaviconURL  string     `json:"favicon_url"`
20	FolderID    *FolderID  `json:"folder_id"`    // nil = root level
21	ShortcutKey *int       `json:"shortcut_key"` // 1-9 for quick access (Alt+1 through Alt+9)
22	Position    int        `json:"position"`     // Order within folder
23	Tags        []Tag      `json:"tags,omitempty"`
24	CreatedAt   time.Time  `json:"created_at"`
25	UpdatedAt   time.Time  `json:"updated_at"`
26}
27
28// NewFavorite creates a new favorite for a URL.
29func NewFavorite(url, title string) *Favorite {
30	now := time.Now()
31	return &Favorite{
32		URL:       url,
33		Title:     title,
34		CreatedAt: now,
35		UpdatedAt: now,
36	}
37}
38
39// HasShortcut returns true if this favorite has a keyboard shortcut.
40func (f *Favorite) HasShortcut() bool {
41	return f.ShortcutKey != nil && *f.ShortcutKey >= 1 && *f.ShortcutKey <= 9
42}
43
44// InFolder returns true if this favorite is in a folder.
45func (f *Favorite) InFolder() bool {
46	return f.FolderID != nil
47}
48
49// HasTag returns true if this favorite has the given tag.
50func (f *Favorite) HasTag(tagID TagID) bool {
51	for _, t := range f.Tags {
52		if t.ID == tagID {
53			return true
54		}
55	}
56	return false
57}
58
59// Folder represents a container for organizing favorites.
60type Folder struct {
61	ID        FolderID  `json:"id"`
62	Name      string    `json:"name"`
63	Icon      string    `json:"icon"`      // Optional icon identifier
64	ParentID  *FolderID `json:"parent_id"` // nil = root level
65	Position  int       `json:"position"`  // Order within parent
66	CreatedAt time.Time `json:"created_at"`
67}
68
69// NewFolder creates a new folder.
70func NewFolder(name string) *Folder {
71	return &Folder{
72		Name:      name,
73		CreatedAt: time.Now(),
74	}
75}
76
77// IsRoot returns true if this folder is at root level.
78func (f *Folder) IsRoot() bool {
79	return f.ParentID == nil
80}
81
82// Tag represents a label that can be applied to favorites.
83type Tag struct {
84	ID        TagID     `json:"id"`
85	Name      string    `json:"name"`
86	Color     string    `json:"color"` // Hex color code (e.g., "#FF5733")
87	CreatedAt time.Time `json:"created_at"`
88}
89
90// NewTag creates a new tag with default color.
91func NewTag(name string) *Tag {
92	return &Tag{
93		Name:      name,
94		Color:     "#808080", // Default gray
95		CreatedAt: time.Now(),
96	}
97}
98
99// FavoriteTree represents a hierarchical view of folders and favorites.
100type FavoriteTree struct {
101	RootFolders    []*Folder
102	RootFavorites  []*Favorite
103	FolderMap      map[FolderID]*Folder     // Quick lookup
104	ChildFolders   map[FolderID][]*Folder   // Children of each folder
105	ChildFavorites map[FolderID][]*Favorite // Favorites in each folder
106}
107
108// NewFavoriteTree creates an empty favorite tree.
109func NewFavoriteTree() *FavoriteTree {
110	return &FavoriteTree{
111		RootFolders:    make([]*Folder, 0),
112		RootFavorites:  make([]*Favorite, 0),
113		FolderMap:      make(map[FolderID]*Folder),
114		ChildFolders:   make(map[FolderID][]*Folder),
115		ChildFavorites: make(map[FolderID][]*Favorite),
116	}
117}

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