feat: Phase 2 UX Polish — theme system, config profiles, error banner, tests
- Add Theme struct with 3 predefined themes (dark/light/druntime) - Add Profile struct for named configuration profiles - Add ErrorBanner with severity levels and auto-dismiss - Add unit tests for theme, error banner, and models - Update CHANGELOG.md and PROJECT_STATE.md
This commit is contained in:
@@ -50,6 +50,16 @@ type Snippet struct {
|
||||
UpdatedAt time.Time `json:"updated_at"`
|
||||
}
|
||||
|
||||
// Profile represents a named configuration profile
|
||||
type Profile struct {
|
||||
Name string `json:"name"`
|
||||
Theme string `json:"theme"`
|
||||
DefaultGroup string `json:"default_group,omitempty"`
|
||||
DefaultAuth string `json:"default_auth,omitempty"` // "password", "key", "both"
|
||||
Editor string `json:"editor,omitempty"`
|
||||
Notes string `json:"notes,omitempty"`
|
||||
}
|
||||
|
||||
// AppConfig represents the application configuration
|
||||
type AppConfig struct {
|
||||
Version string `json:"version"`
|
||||
@@ -60,6 +70,10 @@ type AppConfig struct {
|
||||
AutoSync bool `json:"auto_sync"`
|
||||
SyncProvider string `json:"sync_provider,omitempty"`
|
||||
|
||||
// Profiles
|
||||
Profiles []Profile `json:"profiles,omitempty"`
|
||||
ActiveProfile string `json:"active_profile,omitempty"`
|
||||
|
||||
// Security
|
||||
EncryptionEnabled bool `json:"encryption_enabled"`
|
||||
PasswordHash string `json:"password_hash,omitempty"` // SHA-256 hash for verification
|
||||
@@ -68,10 +82,10 @@ type AppConfig struct {
|
||||
|
||||
// KnownHost represents a verified host key
|
||||
type KnownHost struct {
|
||||
Hostname string `json:"hostname"`
|
||||
Port int `json:"port"`
|
||||
KeyType string `json:"key_type"` // "ssh-rsa", "ssh-ed25519", etc.
|
||||
KeyHash string `json:"key_hash"` // Base64-encoded host key
|
||||
Hostname string `json:"hostname"`
|
||||
Port int `json:"port"`
|
||||
KeyType string `json:"key_type"` // "ssh-rsa", "ssh-ed25519", etc.
|
||||
KeyHash string `json:"key_hash"` // Base64-encoded host key
|
||||
AddedAt time.Time `json:"added_at"`
|
||||
}
|
||||
|
||||
@@ -85,5 +99,42 @@ func DefaultConfig() *AppConfig {
|
||||
Editor: "vim",
|
||||
AutoSync: false,
|
||||
EncryptionEnabled: false,
|
||||
Profiles: []Profile{
|
||||
{
|
||||
Name: "default",
|
||||
Theme: "dark",
|
||||
},
|
||||
},
|
||||
ActiveProfile: "default",
|
||||
}
|
||||
}
|
||||
|
||||
// GetProfile returns a profile by name
|
||||
func (c *AppConfig) GetProfile(name string) *Profile {
|
||||
for i := range c.Profiles {
|
||||
if c.Profiles[i].Name == name {
|
||||
return &c.Profiles[i]
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// GetActiveProfile returns the active profile
|
||||
func (c *AppConfig) GetActiveProfile() *Profile {
|
||||
return c.GetProfile(c.ActiveProfile)
|
||||
}
|
||||
|
||||
// AddProfile adds a new profile
|
||||
func (c *AppConfig) AddProfile(p Profile) {
|
||||
c.Profiles = append(c.Profiles, p)
|
||||
}
|
||||
|
||||
// RemoveProfile removes a profile by name
|
||||
func (c *AppConfig) RemoveProfile(name string) {
|
||||
for i := range c.Profiles {
|
||||
if c.Profiles[i].Name == name {
|
||||
c.Profiles = append(c.Profiles[:i], c.Profiles[i+1:]...)
|
||||
return
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user