Improve mobile/iOS support and simplify theme handling

- Add iOS/mobile meta tags for better web app experience
- Enhance Editor.razor.css for mobile responsiveness and touch
- Simplify theme logic: only light/dark, no "auto" mode
- Remove localStorage and system theme detection from theme.js
- Apply themes via CSS variables for better compatibility
- Update ThemeToggle to match new theme logic and improve UX
This commit is contained in:
Michal Vrba
2026-01-31 12:58:15 +01:00
parent e5edc372fe
commit 5a06a307fb
4 changed files with 90 additions and 56 deletions
+5 -1
View File
@@ -3,7 +3,11 @@
<head>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<meta name="viewport" content="width=device-width, initial-scale=1.0, shrink-to-fit=no" />
<meta name="apple-mobile-web-app-capable" content="yes" />
<meta name="apple-mobile-web-app-status-bar-style" content="black-translucent" />
<meta name="apple-mobile-web-app-title" content="Notemark" />
<meta name="mobile-web-app-capable" content="yes" />
<base href="/" />
<ResourcePreloader />
<link rel="stylesheet" href="@Assets["lib/bootstrap/dist/css/bootstrap.min.css"]" />
+48 -10
View File
@@ -1,5 +1,4 @@
/* Notemark Editor Styles */
.editor-container {
height: 100vh;
display: flex;
@@ -458,37 +457,76 @@
background-color: white;
}
/* Mobile Responsive */
@media (max-width: 768px) {
/* Mobile Responsive - Place at end to override desktop styles */
@media screen and (max-width: 768px) {
.editor-layout.split-view {
flex-direction: column;
flex-direction: column !important;
}
.split-view .editor-pane {
border-right: none;
border-bottom: 1px solid var(--border);
flex: 1;
}
.preview-pane {
flex: 1;
}
.splitter {
display: none;
}
.top-bar {
padding: 0.5rem;
height: auto;
min-height: 50px;
flex-wrap: wrap;
gap: 0.5rem;
}
.top-bar-left,
.top-bar-center,
.top-bar-right {
gap: 0.5rem;
}
.btn-toggle,
.btn-share,
.btn-save,
.btn-new {
font-size: 0.75rem;
padding: 0.375rem 0.75rem;
font-size: 14px;
padding: 8px 12px;
min-height: 44px;
white-space: nowrap;
}
.btn-save {
padding: 0.375rem;
min-width: 2rem;
font-size: 0.875rem;
min-width: 44px;
padding: 8px;
}
.markdown-editor {
font-size: 16px; /* Prevent iOS zoom */
padding: 1rem;
-webkit-overflow-scrolling: touch;
}
.markdown-editor,
.preview-content {
padding: 1rem;
-webkit-overflow-scrolling: touch;
}
/* Share dropdown mobile adjustments */
.share-dropdown {
position: fixed;
top: 50%;
left: 50%;
transform: translate(-50%, -50%);
width: 90vw;
max-width: 320px;
z-index: 1000;
}
}
+12 -28
View File
@@ -5,39 +5,35 @@
</button>
@code {
private string currentTheme = "auto";
private string currentTheme = "light";
protected override async Task OnInitializedAsync()
{
try
{
await JSRuntime.InvokeVoidAsync("notemarkTheme.init");
currentTheme = await JSRuntime.InvokeAsync<string>("notemarkTheme.getCurrentTheme");
}
catch
catch (Exception ex)
{
// Fallback if JS not ready
currentTheme = "auto";
System.Diagnostics.Debug.WriteLine($"Theme init error: {ex.Message}");
currentTheme = "light";
}
}
private async Task ToggleTheme()
{
// Cycle through: auto -> light -> dark -> auto
currentTheme = currentTheme switch
{
"auto" => "light",
"light" => "dark",
"dark" => "auto",
_ => "auto"
};
// Simple toggle: light <-> dark
currentTheme = currentTheme == "light" ? "dark" : "light";
try
{
await JSRuntime.InvokeVoidAsync("notemarkTheme.setTheme", currentTheme);
System.Diagnostics.Debug.WriteLine($"Theme switched to: {currentTheme}");
}
catch
catch (Exception ex)
{
// JS not ready, silently fail
System.Diagnostics.Debug.WriteLine($"Theme toggle error: {ex.Message}");
}
StateHasChanged();
@@ -45,23 +41,11 @@
private string GetThemeIcon()
{
return currentTheme switch
{
"light" => "☀️",
"dark" => "🌙",
"auto" => "🔄",
_ => "🔄"
};
return currentTheme == "dark" ? "🌙" : "☀️";
}
private string GetThemeTooltip()
{
return currentTheme switch
{
"light" => "Switch to dark mode",
"dark" => "Switch to auto mode",
"auto" => "Switch to light mode",
_ => "Toggle theme"
};
return currentTheme == "dark" ? "Switch to light mode" : "Switch to dark mode";
}
}
+24 -16
View File
@@ -1,35 +1,43 @@
// Ultra-simple theme for iOS testing
window.notemarkTheme = {
currentTheme: 'light',
init: function() {
// Get saved theme or default to 'auto'
const savedTheme = localStorage.getItem('notemark-theme') || 'auto';
this.applyTheme(savedTheme);
return savedTheme;
console.log('Simple theme init');
this.applyTheme(this.currentTheme);
return this.currentTheme;
},
setTheme: function(theme) {
localStorage.setItem('notemark-theme', theme);
console.log('Setting theme:', theme);
this.currentTheme = theme;
this.applyTheme(theme);
},
applyTheme: function(theme) {
console.log('Applying theme:', theme);
const root = document.documentElement;
if (theme === 'light') {
root.setAttribute('data-theme', 'light');
} else if (theme === 'dark') {
root.setAttribute('data-theme', 'dark');
if (theme === 'dark') {
root.style.setProperty('--bg', '#1a1a1a');
root.style.setProperty('--surface', '#2d2d2d');
root.style.setProperty('--primary-text', '#ffffff');
root.style.setProperty('--secondary-text', '#cccccc');
root.style.setProperty('--border', '#404040');
root.style.setProperty('--accent', '#007acc');
} else {
// For 'auto', remove data-theme to let CSS @media handle it
root.removeAttribute('data-theme');
root.style.setProperty('--bg', '#ffffff');
root.style.setProperty('--surface', '#f8f9fa');
root.style.setProperty('--primary-text', '#333333');
root.style.setProperty('--secondary-text', '#666666');
root.style.setProperty('--border', '#e9ecef');
root.style.setProperty('--accent', '#007acc');
}
},
getSystemTheme: function() {
return window.matchMedia('(prefers-color-scheme: dark)').matches ? 'dark' : 'light';
console.log('Theme applied successfully');
},
getCurrentTheme: function() {
return localStorage.getItem('notemark-theme') || 'auto';
return this.currentTheme;
}
};