Skip to content

Commit ccab3a4

Browse files
committed
Move tokyo-night seed out of theme package
theme.NewThemeState is back to a pure data constructor. app.go owns the omarchy lookup via newSeededState() so ResetState and NewApp share the same seeding path. Trims TokyoNightDefaults to (palette, wallpaper, ok) — bg and fg were never used — and extracts themeSearchDirs / listBackgrounds helpers shared with LoadAllThemes.
1 parent a5c16e3 commit ccab3a4

4 files changed

Lines changed: 83 additions & 83 deletions

File tree

app.go

Lines changed: 16 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -68,17 +68,16 @@ func (a *App) GetThemeColors() map[string]string {
6868
return a.themeWatcher.CurrentColors()
6969
}
7070

71-
// GetInitialState returns the backend-seeded theme state so the
72-
// frontend can show the right defaults on first paint (e.g. tokyo-night
73-
// palette + wallpaper on omarchy installs).
71+
// GetInitialState returns the current theme state snapshot. Frontend
72+
// pulls this on mount so stores pick up backend-seeded defaults.
7473
func (a *App) GetInitialState() theme.StateSnapshot {
7574
return a.state.Snapshot()
7675
}
7776

7877
// NewApp creates a new App instance.
7978
func NewApp() *App {
8079
return &App{
81-
state: theme.NewThemeState(),
80+
state: newSeededState(),
8281
history: theme.NewHistoryManager(),
8382
writer: theme.NewWriter(EmbeddedTemplates, "templates"),
8483
blueprints: blueprint.NewService(),
@@ -89,6 +88,18 @@ func NewApp() *App {
8988
}
9089
}
9190

91+
// newSeededState builds a ThemeState and, on omarchy systems, overlays
92+
// tokyo-night's palette and 0-* wallpaper as the out-of-the-box
93+
// defaults. Standalone installs get the unmodified DefaultPalette.
94+
func newSeededState() *theme.ThemeState {
95+
s := theme.NewThemeState()
96+
if palette, wallpaper, ok := omarchy.TokyoNightDefaults(); ok {
97+
s.SetPalette(palette)
98+
s.WallpaperPath = wallpaper
99+
}
100+
return s
101+
}
102+
92103
// startup is called by Wails when the application starts.
93104
func (a *App) startup(ctx context.Context) {
94105
a.ctx = ctx
@@ -1089,7 +1100,7 @@ func (a *App) GetTemplateColors() map[string][]string {
10891100
// ResetState resets the theme state to defaults.
10901101
func (a *App) ResetState() {
10911102
a.history.Push(*a.state)
1092-
*a.state = *theme.NewThemeState()
1103+
*a.state = *newSeededState()
10931104
}
10941105

10951106
// ---------------------------------------------------------------------------

frontend/src/App.svelte

Lines changed: 6 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -111,19 +111,20 @@
111111
if (tab) setActiveTab(tab as any);
112112
} catch {}
113113
114-
// Seed stores from backend defaults (tokyo-night on omarchy, blank
115-
// otherwise). Stores init to DEFAULT_PALETTE at module load, so
116-
// this overwrites those before any user interaction.
114+
// Overwrite module-load DEFAULT_PALETTE with backend defaults
115+
// before any user interaction so history starts clean.
117116
try {
118117
const {GetInitialState} = await import('../wailsjs/go/main/App');
119118
const s = await GetInitialState();
120119
if (s?.palette?.length >= 16) {
121-
setPalette(s.palette, true);
120+
setPalette(s.palette, true /* skipHistory */);
122121
}
123122
if (s?.wallpaperPath) {
124123
setWallpaperPath(s.wallpaperPath);
125124
}
126-
} catch {}
125+
} catch (e) {
126+
console.warn('GetInitialState failed:', e);
127+
}
127128
128129
initKeyboardShortcuts();
129130

internal/omarchy/themes.go

Lines changed: 59 additions & 60 deletions
Original file line numberDiff line numberDiff line change
@@ -20,21 +20,55 @@ type Theme struct {
2020
IsAetherGenerated bool `json:"isAetherGenerated"`
2121
}
2222

23-
// LoadAllThemes discovers themes from user and system directories.
24-
func LoadAllThemes() ([]Theme, error) {
23+
// themeSearchDirs returns the user and system-wide directories where
24+
// omarchy looks up themes, in precedence order.
25+
func themeSearchDirs() []string {
2526
home, err := os.UserHomeDir()
2627
if err != nil {
27-
return nil, err
28+
return nil
29+
}
30+
return []string{
31+
filepath.Join(home, ".config", "omarchy", "themes"),
32+
filepath.Join(home, ".local", "share", "omarchy", "themes"),
33+
}
34+
}
35+
36+
func isImageFile(name string) bool {
37+
switch strings.ToLower(filepath.Ext(name)) {
38+
case ".jpg", ".jpeg", ".png", ".webp":
39+
return true
40+
}
41+
return false
42+
}
43+
44+
// listBackgrounds returns absolute paths of image files in dir, sorted
45+
// by name (os.ReadDir's default).
46+
func listBackgrounds(dir string) []string {
47+
entries, err := os.ReadDir(dir)
48+
if err != nil {
49+
return nil
2850
}
51+
var paths []string
52+
for _, e := range entries {
53+
if isImageFile(e.Name()) {
54+
paths = append(paths, filepath.Join(dir, e.Name()))
55+
}
56+
}
57+
return paths
58+
}
2959

30-
userDir := filepath.Join(home, ".config", "omarchy", "themes")
31-
sysDir := filepath.Join(home, ".local", "share", "omarchy", "themes")
60+
// LoadAllThemes discovers themes from user and system directories.
61+
func LoadAllThemes() ([]Theme, error) {
62+
dirs := themeSearchDirs()
63+
if dirs == nil {
64+
return nil, os.ErrNotExist
65+
}
3266
currentName := GetCurrentThemeName()
3367

3468
seen := make(map[string]bool)
3569
var themes []Theme
3670

37-
for _, dir := range []string{userDir, sysDir} {
71+
for _, dir := range dirs {
3872
entries, err := os.ReadDir(dir)
3973
if err != nil {
4074
continue
@@ -59,41 +93,25 @@ func LoadAllThemes() ([]Theme, error) {
5993
IsCurrentTheme: name == currentName,
6094
}
6195

62-
// Check for symlink (ReadDir doesn't always report it)
63-
if target, err := os.Readlink(themePath); err == nil {
96+
// ReadDir doesn't always flag symlinks on the DirEntry.
97+
if _, err := os.Readlink(themePath); err == nil {
6498
theme.IsSymlink = true
65-
_ = target
6699
}
67100

68-
// Try colors.toml first
69-
tomlPath := filepath.Join(themePath, "colors.toml")
70-
if data, err := os.ReadFile(tomlPath); err == nil {
101+
if data, err := os.ReadFile(filepath.Join(themePath, "colors.toml")); err == nil {
71102
colors, bg, fg := ParseColorsToml(string(data))
72103
theme.Colors = colors[:]
73104
theme.Background = bg
74105
theme.Foreground = fg
75106
theme.IsAetherGenerated = true
76-
} else {
77-
// Fall back to kitty.conf
78-
kittyPath := filepath.Join(themePath, "kitty.conf")
79-
if data, err := os.ReadFile(kittyPath); err == nil {
80-
colors, bg, fg := ParseKittyConf(string(data))
81-
theme.Colors = colors[:]
82-
theme.Background = bg
83-
theme.Foreground = fg
84-
}
107+
} else if data, err := os.ReadFile(filepath.Join(themePath, "kitty.conf")); err == nil {
108+
colors, bg, fg := ParseKittyConf(string(data))
109+
theme.Colors = colors[:]
110+
theme.Background = bg
111+
theme.Foreground = fg
85112
}
86113

87-
// Scan wallpapers
88-
bgDir := filepath.Join(themePath, "backgrounds")
89-
if entries, err := os.ReadDir(bgDir); err == nil {
90-
for _, e := range entries {
91-
ext := strings.ToLower(filepath.Ext(e.Name()))
92-
if ext == ".jpg" || ext == ".jpeg" || ext == ".png" || ext == ".webp" {
93-
theme.Wallpapers = append(theme.Wallpapers, filepath.Join(bgDir, e.Name()))
94-
}
95-
}
96-
}
114+
theme.Wallpapers = listBackgrounds(filepath.Join(themePath, "backgrounds"))
97115

98116
themes = append(themes, theme)
99117
}
@@ -107,40 +125,21 @@ func LoadAllThemes() ([]Theme, error) {
107125
}
108126

109127
// TokyoNightDefaults loads the tokyo-night palette and its first
110-
// wallpaper from a local omarchy install, for use as Aether's
111-
// out-of-the-box defaults. Returns ok=false when the theme isn't
112-
// present (e.g. standalone installs without omarchy).
113-
func TokyoNightDefaults() (palette [16]string, bg, fg, wallpaper string, ok bool) {
114-
home, err := os.UserHomeDir()
115-
if err != nil {
116-
return
117-
}
118-
candidates := []string{
119-
filepath.Join(home, ".config", "omarchy", "themes", "tokyo-night"),
120-
filepath.Join(home, ".local", "share", "omarchy", "themes", "tokyo-night"),
121-
}
122-
123-
for _, themeDir := range candidates {
128+
// wallpaper (the "0-" file, by omarchy's naming convention) from a
129+
// local omarchy install. Returns ok=false on standalone systems where
130+
// the theme isn't present.
131+
func TokyoNightDefaults() (palette [16]string, wallpaper string, ok bool) {
132+
for _, root := range themeSearchDirs() {
133+
themeDir := filepath.Join(root, "tokyo-night")
124134
data, err := os.ReadFile(filepath.Join(themeDir, "colors.toml"))
125135
if err != nil {
126136
continue
127137
}
128-
palette, bg, fg = ParseColorsToml(string(data))
129-
130-
// os.ReadDir returns entries sorted by filename, so the first
131-
// image is tokyo-night's "0-*" wallpaper by convention.
132-
if entries, err := os.ReadDir(filepath.Join(themeDir, "backgrounds")); err == nil {
133-
for _, e := range entries {
134-
ext := strings.ToLower(filepath.Ext(e.Name()))
135-
if ext == ".jpg" || ext == ".jpeg" || ext == ".png" || ext == ".webp" {
136-
wallpaper = filepath.Join(themeDir, "backgrounds", e.Name())
137-
break
138-
}
139-
}
138+
palette, _, _ = ParseColorsToml(string(data))
139+
if bgs := listBackgrounds(filepath.Join(themeDir, "backgrounds")); len(bgs) > 0 {
140+
wallpaper = bgs[0]
140141
}
141-
142-
ok = true
143-
return
142+
return palette, wallpaper, true
144143
}
145144
return
146145
}

internal/theme/state.go

Lines changed: 2 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,6 @@ package theme
22

33
import (
44
"aether/internal/color"
5-
"aether/internal/omarchy"
65
"aether/internal/template"
76
)
87

@@ -42,20 +41,10 @@ var DefaultPalette = [16]string{
4241
}
4342

4443
// NewThemeState returns a ThemeState initialised with default values.
45-
// On omarchy systems it seeds the palette and wallpaper from the
46-
// installed tokyo-night theme; standalone installs keep DefaultPalette.
4744
func NewThemeState() *ThemeState {
48-
palette := DefaultPalette
49-
var wallpaper string
50-
if p, _, _, w, ok := omarchy.TokyoNightDefaults(); ok {
51-
palette = p
52-
wallpaper = w
53-
}
54-
5545
s := &ThemeState{
56-
Palette: palette,
57-
BasePalette: palette,
58-
WallpaperPath: wallpaper,
46+
Palette: DefaultPalette,
47+
BasePalette: DefaultPalette,
5948
LockedColors: make(map[int]bool),
6049
Adjustments: color.DefaultAdjustments(),
6150
ExtendedColors: make(map[string]string),

0 commit comments

Comments
 (0)