Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
12 changes: 12 additions & 0 deletions backend/main.py
Original file line number Diff line number Diff line change
Expand Up @@ -260,6 +260,16 @@ def safe_error_message(error: Exception, user_message: str = "An error occurred"
_autosave_raw = 1000
AUTOSAVE_DELAY_MS = max(250, min(60000, _autosave_raw))

# Default UI theme for browsers that do not have a saved preference yet.
DEFAULT_THEME = str(config.get('ui', {}).get('default_theme', 'light')).strip() or 'light'
_themes_dir = Path(__file__).parent.parent / "themes"
if not get_theme_css(str(_themes_dir), DEFAULT_THEME):
logger.warning(
"Configured ui.default_theme %r was not found; falling back to 'light'",
DEFAULT_THEME,
)
DEFAULT_THEME = 'light'

if DEMO_MODE:
# Enable rate limiting for demo deployments
limiter = Limiter(key_func=get_remote_address, default_limits=["200/hour"])
Expand Down Expand Up @@ -460,6 +470,7 @@ async def login_page(request: Request, error: str = None):
# Inject app name throughout the login page
app_name = config['app']['name']
content = content.replace('NoteDiscovery', app_name)
content = content.replace('__DEFAULT_THEME__', DEFAULT_THEME)

return content

Expand Down Expand Up @@ -520,6 +531,7 @@ async def get_config():
"demoMode": DEMO_MODE, # Expose demo mode flag to frontend
"alreadyDonated": ALREADY_DONATED, # Hide support buttons if true
"autosaveDelayMs": AUTOSAVE_DELAY_MS, # Debounce for note/drawing autosave
"defaultTheme": DEFAULT_THEME, # Used when the browser has no saved preference
"authentication": {
"enabled": config.get('authentication', {}).get('enabled', False)
}
Expand Down
5 changes: 4 additions & 1 deletion config.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,10 @@ search:

# User interface behavior
ui:
# Theme used when a browser has not saved a theme preference yet.
# Use a theme ID from the themes directory (the CSS filename without .css).
default_theme: "light"

# Autosave debounce in milliseconds (applies to note typing and drawing autosave).
# Lower = saves more often (more disk writes); higher = saves less often.
# Override via the AUTOSAVE_DELAY_MS env var. Server clamps to 250-60000ms.
Expand Down Expand Up @@ -59,4 +63,3 @@ authentication:
#
# Leave empty to disable API key authentication (only session auth works)
api_key: ""

4 changes: 3 additions & 1 deletion documentation/ENVIRONMENT_VARIABLES.md
Original file line number Diff line number Diff line change
Expand Up @@ -113,6 +113,9 @@ Equivalent in `config.yaml`:
```yaml
ui:
autosave_delay_ms: 5000
# Used only when the browser has no saved theme preference.
# Set this to a CSS filename from themes/ without the .css suffix.
default_theme: "dracula"
```

## 🎯 Configuration Priority
Expand Down Expand Up @@ -178,4 +181,3 @@ When `debug: false` (recommended):
---

**Pro Tip:** Use environment variables for **deployment-specific** settings, and `config.yaml` for **application defaults**. This keeps your configuration flexible and maintainable! 🎯

3 changes: 2 additions & 1 deletion documentation/THEMES.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,8 @@

NoteDiscovery ships with **several built-in themes** (light and dark styles). Open **Settings → Theme** to browse what is available; your choice is saved automatically.

To choose the theme shown to new browsers, set `ui.default_theme` in `config.yaml` to a theme ID (the CSS filename without `.css`). A theme previously selected in the browser is stored in `localStorage` and takes priority over this default.

The set can grow over time—see the `themes/` folder in the repository for the current files. You can also add your own (see below) or override themes when self-hosting.

## Create Custom Themes
Expand Down Expand Up @@ -143,4 +145,3 @@ All these CSS variables **must** be defined for your theme to work properly:
---

🎨 **Tip:** Use browser DevTools to experiment with colors in real-time before creating your theme!

9 changes: 6 additions & 3 deletions frontend/app.js
Original file line number Diff line number Diff line change
Expand Up @@ -261,6 +261,7 @@ function noteApp() {
demoMode: false,
alreadyDonated: false,
autosaveDelayMs: CONFIG.AUTOSAVE_DELAY, // hydrated from /api/config in loadConfig()
defaultTheme: 'light',
notes: [],

// True while /api/notes is in flight. Drives the "Loading your vault…"
Expand Down Expand Up @@ -971,6 +972,9 @@ function noteApp() {
if (Number.isFinite(config.autosaveDelayMs) && config.autosaveDelayMs > 0) {
this.autosaveDelayMs = config.autosaveDelayMs;
}
if (typeof config.defaultTheme === 'string' && config.defaultTheme) {
this.defaultTheme = config.defaultTheme;
}
} catch (error) {
console.error('Failed to load config:', error);
}
Expand All @@ -996,8 +1000,8 @@ function noteApp() {

// Initialize theme system
async initTheme() {
// Load saved theme preference from localStorage
const savedTheme = localStorage.getItem('noteDiscoveryTheme') || 'light';
// A user's saved preference takes priority over the configured default.
const savedTheme = localStorage.getItem('noteDiscoveryTheme') || this.defaultTheme;
this.currentTheme = savedTheme;
await this.applyTheme(savedTheme);
},
Expand Down Expand Up @@ -7731,4 +7735,3 @@ function noteApp() {
}
}
}

3 changes: 1 addition & 2 deletions frontend/login.html
Original file line number Diff line number Diff line change
Expand Up @@ -51,7 +51,7 @@
<script>
// Load theme immediately (same approach as index.html)
(async function() {
const savedTheme = localStorage.getItem('noteDiscoveryTheme') || 'light';
const savedTheme = localStorage.getItem('noteDiscoveryTheme') || '__DEFAULT_THEME__';

try {
const response = await fetch(`/api/themes/${savedTheme}`);
Expand Down Expand Up @@ -282,4 +282,3 @@ <h1>NoteDiscovery</h1>
</script>
</body>
</html>