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}