mirror of
https://gitlab.com/ArkHost/HelixNotes.git
synced 2026-07-24 07:45:57 +02:00
164 lines
4.7 KiB
TypeScript
164 lines
4.7 KiB
TypeScript
import { writable, derived } from "svelte/store";
|
|
import type {
|
|
AppConfig,
|
|
NoteEntry,
|
|
NoteContent,
|
|
NotebookEntry,
|
|
VaultState,
|
|
ViewMode,
|
|
SortMode,
|
|
} from "$lib/types";
|
|
|
|
// App state
|
|
export const appConfig = writable<AppConfig | null>(null);
|
|
export const vaultReady = writable(false);
|
|
|
|
// UI state
|
|
export const viewMode = writable<ViewMode>("all");
|
|
export const sortMode = writable<SortMode>("modified");
|
|
export const sidebarCollapsed = writable(false);
|
|
export const sidebarWidth = writable(220);
|
|
export const notelistWidth = writable(280);
|
|
export const searchQuery = writable("");
|
|
export const showCommandPalette = writable(false);
|
|
export const showSearch = writable(false);
|
|
export const showSettings = writable(false);
|
|
export const settingsTab = writable<string | null>(null);
|
|
export const showInfo = writable(false);
|
|
export const notebookIcons = writable<Record<string, string>>({});
|
|
export const quickAccessPaths = writable<string[]>([]);
|
|
export const collapsedNotebooks = writable<string[]>([]);
|
|
|
|
// Data
|
|
export const notebooks = writable<NotebookEntry[]>([]);
|
|
export const notes = writable<NoteEntry[]>([]);
|
|
export const tags = writable<[string, number][]>([]);
|
|
export const activeNote = writable<NoteContent | null>(null);
|
|
export const activeNotePath = writable<string | null>(null);
|
|
export const activeNotebook = writable<NotebookEntry | null>(null);
|
|
export const activeTag = writable<string | null>(null);
|
|
|
|
// Mobile state
|
|
export const mobileView = writable<"sidebar" | "notelist" | "editor">(
|
|
"sidebar",
|
|
);
|
|
|
|
// Editor state
|
|
export const editorDirty = writable(false);
|
|
export const sourceMode = writable(false);
|
|
export const focusMode = writable(false);
|
|
export const readOnly = writable(false);
|
|
|
|
// Theme
|
|
export const theme = writable<string>("system");
|
|
|
|
// Update state
|
|
export const updateAvailable = writable<{
|
|
version: string;
|
|
body?: string;
|
|
} | null>(null);
|
|
export const updateObj = writable<any>(null);
|
|
export const installType = writable<string>("native");
|
|
export const androidApkUrl = writable<string | null>(null);
|
|
|
|
export async function checkForUpdate() {
|
|
try {
|
|
const { check } = await import("@tauri-apps/plugin-updater");
|
|
const update = await check();
|
|
if (update) {
|
|
updateAvailable.set({ version: update.version, body: update.body });
|
|
updateObj.set(update);
|
|
}
|
|
} catch {
|
|
// Silent fail — don't disrupt app startup
|
|
}
|
|
}
|
|
|
|
function isNewerVersion(remote: string, local: string): boolean {
|
|
const r = remote.split(".").map(Number);
|
|
const l = local.split(".").map(Number);
|
|
for (let i = 0; i < Math.max(r.length, l.length); i++) {
|
|
const rv = r[i] || 0;
|
|
const lv = l[i] || 0;
|
|
if (rv > lv) return true;
|
|
if (rv < lv) return false;
|
|
}
|
|
return false;
|
|
}
|
|
|
|
export async function checkForUpdateMobile() {
|
|
try {
|
|
const { getVersion } = await import("@tauri-apps/api/app");
|
|
const currentVersion = await getVersion();
|
|
const res = await fetch("https://helixnotes.com/latest.json");
|
|
if (!res.ok) return;
|
|
const data = await res.json();
|
|
if (data.version && isNewerVersion(data.version, currentVersion)) {
|
|
updateAvailable.set({ version: data.version, body: data.notes });
|
|
const android = data.platforms?.["android-universal"];
|
|
if (android?.url) {
|
|
androidApkUrl.set(android.url);
|
|
}
|
|
}
|
|
} catch {
|
|
// Silent fail
|
|
}
|
|
}
|
|
|
|
// Derived
|
|
export const sortedNotes = derived(
|
|
[notes, sortMode, viewMode],
|
|
([$notes, $sortMode, $viewMode]) => {
|
|
// Quick Access preserves stored order
|
|
if ($viewMode === "quickaccess") return $notes;
|
|
|
|
const pinned = $notes.filter((n) => n.meta.pinned);
|
|
const unpinned = $notes.filter((n) => !n.meta.pinned);
|
|
|
|
const sortFn = (a: NoteEntry, b: NoteEntry) => {
|
|
switch ($sortMode) {
|
|
case "title":
|
|
return a.meta.title.localeCompare(b.meta.title);
|
|
case "created":
|
|
return (
|
|
new Date(b.meta.created).getTime() -
|
|
new Date(a.meta.created).getTime()
|
|
);
|
|
case "modified":
|
|
default:
|
|
return (
|
|
new Date(b.meta.modified).getTime() -
|
|
new Date(a.meta.modified).getTime()
|
|
);
|
|
}
|
|
};
|
|
|
|
return [...pinned.sort(sortFn), ...unpinned.sort(sortFn)];
|
|
},
|
|
);
|
|
|
|
export const vaultState = derived(
|
|
[
|
|
activeNotePath,
|
|
sidebarWidth,
|
|
notelistWidth,
|
|
sidebarCollapsed,
|
|
collapsedNotebooks,
|
|
],
|
|
([
|
|
$activeNotePath,
|
|
$sidebarWidth,
|
|
$notelistWidth,
|
|
$sidebarCollapsed,
|
|
$collapsedNotebooks,
|
|
]) => {
|
|
return {
|
|
last_open_note: $activeNotePath,
|
|
sidebar_width: $sidebarWidth,
|
|
notelist_width: $notelistWidth,
|
|
sidebar_collapsed: $sidebarCollapsed,
|
|
collapsed_notebooks: $collapsedNotebooks,
|
|
} satisfies VaultState;
|
|
},
|
|
);
|