Skip to content
Merged
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
40 changes: 33 additions & 7 deletions src-tauri/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -159,6 +159,14 @@ fn send_markdown_path(state: State<'_, AppState>) -> Vec<String> {
files
}

#[tauri::command]
fn save_theme(app: AppHandle, theme: String) -> Result<(), String> {
let config_dir = app.path().app_config_dir().map_err(|e| e.to_string())?;
fs::create_dir_all(&config_dir).map_err(|e| e.to_string())?;
let theme_path = config_dir.join("theme.txt");
fs::write(theme_path, theme).map_err(|e| e.to_string())
}

#[tauri::command]
async fn get_app_mode() -> String {

Expand Down Expand Up @@ -415,7 +423,7 @@ pub fn run() {

let _window = tauri::WebviewWindowBuilder::new(app, label, tauri::WebviewUrl::App("index.html".into()))
.title("Markpad")
.inner_size(850.0, 650.0)
.inner_size(900.0, 650.0)
.min_inner_size(400.0, 300.0)
.visible(false)
.resizable(true)
Expand All @@ -425,11 +433,28 @@ pub fn run() {
.visible(false)
.build()?;

#[cfg(target_os = "windows")]
{
use tauri::window::Color;
let _ = _window.set_background_color(Some(Color(18, 18, 18, 255)));
}
let config_dir = app.path().app_config_dir()?;
let theme_path = config_dir.join("theme.txt");
let theme_pref = fs::read_to_string(theme_path).unwrap_or_else(|_| "system".to_string());

let window = app.get_webview_window(label).unwrap();

let bg_color = match theme_pref.as_str() {
"dark" => Some(tauri::window::Color(24, 24, 24, 255)),
"light" => Some(tauri::window::Color(253, 253, 253, 255)),
_ => {
if let Ok(t) = window.theme() {
match t {
tauri::Theme::Dark => Some(tauri::window::Color(24, 24, 24, 255)),
_ => Some(tauri::window::Color(253, 253, 253, 255)),
}
} else {
Some(tauri::window::Color(253, 253, 253, 255))
}
}
};

let _ = window.set_background_color(bg_color);

let _ = _window.set_shadow(true);

Expand Down Expand Up @@ -469,7 +494,8 @@ pub fn run() {
unwatch_file,

show_context_menu,
show_window
show_window,
save_theme
])
.build(tauri::generate_context!())
.expect("error while building tauri application")
Expand Down
20 changes: 20 additions & 0 deletions src/app.html
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,26 @@
<html lang="en">

<head>
<script>
(function () {
try {
var stored = localStorage.getItem('theme');
var theme = stored;
if (!theme || theme === 'system') {
theme = window.matchMedia('(prefers-color-scheme: dark)').matches ? 'dark' : 'light';
}

if (stored === 'dark' || stored === 'light') {
document.documentElement.setAttribute('data-theme', stored);
}

var bg = theme === 'dark' ? '#181818' : '#FDFDFD';
document.documentElement.style.backgroundColor = bg;
} catch (e) {
console.error(e);
}
})();
</script>
<meta charset="utf-8" />
<link rel="icon" href="%sveltekit.assets%/favicon.png" />
<meta name="viewport" content="width=device-width, initial-scale=1" />
Expand Down
50 changes: 44 additions & 6 deletions src/lib/Installer.svelte
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
<script lang="ts">
import { invoke } from '@tauri-apps/api/core';
import { getVersion } from '@tauri-apps/api/app';
import { getCurrentWindow } from '@tauri-apps/api/window';
import { onMount } from 'svelte';
import iconUrl from '../assets/icon.png';
Expand All @@ -11,6 +12,7 @@
let checking = $state(true);
let isInstalled = $state(false);
let installedVersion = $state('');
let installerVersion = $state('');
let installedAllUsers = $state(false);

let allUsers = $state(false);
Expand Down Expand Up @@ -83,7 +85,12 @@
await appWindow.close();
}

onMount(() => {
onMount(async () => {
try {
installerVersion = await getVersion();
} catch (e) {
console.error('Failed to get installer version:', e);
}
checkStatus();
});
</script>
Expand All @@ -98,11 +105,15 @@
<div class="content">
<div class="header">
<img src={iconUrl} alt="App Icon" class="app-icon" />
<h1>Markdown Viewer</h1>
{#if isInstalled}
<h1>Markdown Viewer</h1>
<div class="version-comparison">
<span class="v-label">Current:</span> v{installedVersion}
<span class="v-arrow">→</span>
<span class="v-label">Target:</span> v{installerVersion}
</div>
{:else}
<h1>Markdown Viewer</h1>
<p class="subtitle">A simple markdown viewer</p>
<p class="subtitle">A simple markdown viewer <span class="v-lite">v{installerVersion}</span></p>
{/if}
</div>

Expand Down Expand Up @@ -252,12 +263,12 @@
width: 70px;
height: 70px;
margin-bottom: 12px;
filter: drop-shadow(0 4px 12px rgba(0, 0, 0, 0.1));
filter: invert(0.8) drop-shadow(0 4px 12px rgba(0, 0, 0, 0.1));
}

@media (prefers-color-scheme: dark) {
.app-icon {
filter: invert(1) drop-shadow(0 4px 12px rgba(0, 0, 0, 0.1));
filter: invert(0) drop-shadow(0 4px 12px rgba(0, 0, 0, 0.1));
}
}

Expand Down Expand Up @@ -489,4 +500,31 @@
transform: translateY(0);
}
}

.version-comparison {
font-size: 11px;
margin-top: 8px;
opacity: 0.6;
display: flex;
align-items: center;
justify-content: center;
gap: 6px;
font-weight: 500;
}

.v-label {
opacity: 0.6;
font-weight: 400;
}

.v-arrow {
color: var(--color-accent-fg);
font-weight: bold;
}

.v-lite {
margin-left: 4px;
opacity: 0.4;
font-size: 11px;
}
</style>
5 changes: 4 additions & 1 deletion src/lib/MarkdownViewer.svelte
Original file line number Diff line number Diff line change
Expand Up @@ -62,10 +62,13 @@
onMount(() => {
const storedTheme = localStorage.getItem('theme') as 'system' | 'dark' | 'light' | null;
if (storedTheme) theme = storedTheme;
// Clear the forced background color from app.html
document.documentElement.style.removeProperty('background-color');
});

$effect(() => {
localStorage.setItem('theme', theme);
invoke('save_theme', { theme }).catch(console.error);

if (theme === 'system') {
delete document.documentElement.dataset.theme;
Expand Down Expand Up @@ -188,7 +191,7 @@
if (img.hasAttribute('title')) media.setAttribute('title', img.getAttribute('title')!);

img.replaceWith(media);
continue;
continue;
}

if (isYoutubeLink(src)) {
Expand Down
10 changes: 10 additions & 0 deletions src/lib/components/Editor.svelte
Original file line number Diff line number Diff line change
Expand Up @@ -117,6 +117,7 @@
wordWrap: settings.wordWrap as 'on' | 'off' | 'wordWrapColumn' | 'bounded',
lineNumbers: settings.lineNumbers as 'on' | 'off' | 'relative' | 'interval',
renderLineHighlight: settings.renderLineHighlight ? 'line' : 'none',
occurrencesHighlight: settings.occurrencesHighlight ? 'singleFile' : 'off',
});

if (tabManager.activeTab?.editorViewState) {
Expand Down Expand Up @@ -196,6 +197,14 @@
},
});

editor.addAction({
id: 'toggle-occurrences-highlight',
label: 'Toggle Occurrences Highlight',
run: () => {
settings.toggleOccurrencesHighlight();
},
});

editor.addAction({
id: 'toggle-tabs',
label: 'Toggle Tabs',
Expand Down Expand Up @@ -526,6 +535,7 @@
wordWrap: settings.wordWrap as 'on' | 'off' | 'wordWrapColumn' | 'bounded',
lineNumbers: settings.lineNumbers as 'on' | 'off' | 'relative' | 'interval',
renderLineHighlight: settings.renderLineHighlight as 'line' | 'none',
occurrencesHighlight: settings.occurrencesHighlight ? 'singleFile' : 'off',
fontSize: 14 * (zoomLevel / 100),
});
}
Expand Down
23 changes: 23 additions & 0 deletions src/lib/components/HomePage.svelte
Original file line number Diff line number Diff line change
@@ -1,4 +1,7 @@
<script lang="ts">
import { getVersion } from '@tauri-apps/api/app';
import { onMount } from 'svelte';

let { recentFiles, onselectFile, onloadFile, onremoveRecentFile, onnewFile } = $props<{
recentFiles: string[];
onselectFile: () => void;
Expand All @@ -7,6 +10,16 @@
onnewFile: () => void;
}>();

let version = $state('');

onMount(async () => {
try {
version = await getVersion();
} catch (e) {
console.error('Failed to get version:', e);
}
});

function getFileName(path: string) {
return path.split(/[/\\]/).pop() || path;
}
Expand Down Expand Up @@ -93,6 +106,7 @@
<p class="empty-recent">Your recently opened files will appear here.</p>
{/if}
</div>
<div class="version-tag">v{version}</div>
</div>

<style>
Expand Down Expand Up @@ -281,4 +295,13 @@
opacity: 1 !important;
background: rgba(255, 0, 0, 0.1);
}

.version-tag {
margin-top: auto;
padding-bottom: 20px;
font-size: 10px;
opacity: 0.25;
font-weight: 500;
pointer-events: none;
}
</style>
5 changes: 4 additions & 1 deletion src/lib/components/TitleBar.svelte
Original file line number Diff line number Diff line change
Expand Up @@ -315,9 +315,12 @@
onclick={(e) => {
e.stopPropagation();
themeMenuOpen = !themeMenuOpen;
if (themeMenuOpen) hideTooltip();
}}
aria-label="Change Theme"
onmouseenter={(e) => showTooltip(e, 'Change Theme')}
onmouseenter={(e) => {
if (!themeMenuOpen) showTooltip(e, 'Change Theme');
}}
onmouseleave={hideTooltip}
transition:fly={{ x: 10, duration: 200 }}>
{#if theme === 'light'}
Expand Down
8 changes: 8 additions & 0 deletions src/lib/stores/settings.svelte.ts
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ export class SettingsStore {
minimap: boolean;
lineNumbers: string;
} | null>(null);
occurrencesHighlight = $state(false);

constructor() {
if (typeof localStorage !== 'undefined') {
Expand All @@ -29,6 +30,7 @@ export class SettingsStore {
const savedShowTabs = localStorage.getItem('editor.showTabs');
const savedZenMode = localStorage.getItem('editor.zenMode');
const savedPreZenState = localStorage.getItem('editor.preZenState');
const savedOccurrencesHighlight = localStorage.getItem('editor.occurrencesHighlight');

if (savedMinimap !== null) this.minimap = savedMinimap === 'true';
if (savedWordWrap !== null) this.wordWrap = savedWordWrap;
Expand All @@ -40,6 +42,7 @@ export class SettingsStore {
if (savedRenderLineHighlight !== null) this.renderLineHighlight = savedRenderLineHighlight;
if (savedShowTabs !== null) this.showTabs = savedShowTabs === 'true';
if (savedZenMode !== null) this.zenMode = savedZenMode === 'true';
if (savedOccurrencesHighlight !== null) this.occurrencesHighlight = savedOccurrencesHighlight === 'true';
if (savedPreZenState !== null) {
try {
this.preZenState = JSON.parse(savedPreZenState);
Expand All @@ -60,6 +63,7 @@ export class SettingsStore {
localStorage.setItem('editor.renderLineHighlight', this.renderLineHighlight);
localStorage.setItem('editor.showTabs', String(this.showTabs));
localStorage.setItem('editor.zenMode', String(this.zenMode));
localStorage.setItem('editor.occurrencesHighlight', String(this.occurrencesHighlight));
if (this.preZenState) {
localStorage.setItem('editor.preZenState', JSON.stringify(this.preZenState));
} else {
Expand Down Expand Up @@ -128,6 +132,10 @@ export class SettingsStore {
}
}
}

toggleOccurrencesHighlight() {
this.occurrencesHighlight = !this.occurrencesHighlight;
}
}

export const settings = new SettingsStore();
4 changes: 4 additions & 0 deletions src/styles.css
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,7 @@ body {
--color-done-fg: #8250df;
--color-done-emphasis: #8250df;
--color-window-border-top: #B5B5B5;
--color-canvas-overlay: #FDFDFD;
--tab-active-bg: #dee1e6;

/* Light Syntax Highlighting */
Expand Down Expand Up @@ -78,6 +79,7 @@ body {
--color-done-fg: #8250df;
--color-done-emphasis: #8250df;
--color-window-border-top: #B5B5B5;
--color-canvas-overlay: #FDFDFD;
--tab-active-bg: #dee1e6;

/* Light Syntax Highlighting */
Expand Down Expand Up @@ -114,6 +116,7 @@ body {
--color-done-fg: #a371f7;
--color-done-emphasis: #8957e5;
--color-window-border-top: #3E3E3E;
--color-canvas-overlay: #2d2e30;
--tab-active-bg: #2d2e30;

/* Dark Syntax Highlighting */
Expand Down Expand Up @@ -151,6 +154,7 @@ body {
--color-done-fg: #a371f7;
--color-done-emphasis: #8957e5;
--color-window-border-top: #3E3E3E;
--color-canvas-overlay: #2d2e30;
--tab-active-bg: #2d2e30;

/* Dark Syntax Highlighting */
Expand Down