Compare commits
3 Commits
0.1.1
...
61fb56fa14
| Author | SHA1 | Date | |
|---|---|---|---|
| 61fb56fa14 | |||
| 8039a3545d | |||
| fe0476218d |
@@ -6,4 +6,5 @@ flatpak/.build/
|
|||||||
flatpak/.repo/
|
flatpak/.repo/
|
||||||
flatpak/.flatpak-builder/
|
flatpak/.flatpak-builder/
|
||||||
flatpak/pena.deb
|
flatpak/pena.deb
|
||||||
|
flatpak/icon.png
|
||||||
flatpak/*.flatpak
|
flatpak/*.flatpak
|
||||||
|
|||||||
@@ -6,11 +6,13 @@
|
|||||||
# 1. `cargo tauri build --bundles deb` -> produit le .deb autonome
|
# 1. `cargo tauri build --bundles deb` -> produit le .deb autonome
|
||||||
# 2. Copie du .deb à côté du manifeste sous le nom `pena.deb`
|
# 2. Copie du .deb à côté du manifeste sous le nom `pena.deb`
|
||||||
# 3. `flatpak-builder` construit le bundle dans la sandbox GNOME
|
# 3. `flatpak-builder` construit le bundle dans la sandbox GNOME
|
||||||
# 4. Installation locale (--user) et/ou export en fichier .flatpak
|
# 4. Installation locale (--user) ET export du fichier pena.flatpak
|
||||||
|
#
|
||||||
|
# Le fichier `pena.flatpak` est TOUJOURS exporté à côté du script.
|
||||||
#
|
#
|
||||||
# Usage :
|
# Usage :
|
||||||
# ./build-flatpak.sh # build + installation locale (--user)
|
# ./build-flatpak.sh # build + installation (--user) + pena.flatpak
|
||||||
# ./build-flatpak.sh --bundle # build + export d'un fichier Pena.flatpak
|
# ./build-flatpak.sh --no-install # build + pena.flatpak seul (pas d'installation)
|
||||||
# ./build-flatpak.sh --no-deb # réutilise le .deb déjà présent (build rapide)
|
# ./build-flatpak.sh --no-deb # réutilise le .deb déjà présent (build rapide)
|
||||||
#
|
#
|
||||||
set -euo pipefail
|
set -euo pipefail
|
||||||
@@ -28,13 +30,13 @@ DEB_TARGET="$SCRIPT_DIR/pena.deb"
|
|||||||
TAURI_CONF="$PROJECT_DIR/src-tauri/tauri.conf.json"
|
TAURI_CONF="$PROJECT_DIR/src-tauri/tauri.conf.json"
|
||||||
METAINFO="$SCRIPT_DIR/${APP_ID}.metainfo.xml"
|
METAINFO="$SCRIPT_DIR/${APP_ID}.metainfo.xml"
|
||||||
|
|
||||||
DO_BUNDLE=0
|
DO_INSTALL=1
|
||||||
BUILD_DEB=1
|
BUILD_DEB=1
|
||||||
for arg in "$@"; do
|
for arg in "$@"; do
|
||||||
case "$arg" in
|
case "$arg" in
|
||||||
--bundle) DO_BUNDLE=1 ;;
|
--no-install|--bundle) DO_INSTALL=0 ;; # --bundle : alias rétrocompatible
|
||||||
--no-deb) BUILD_DEB=0 ;;
|
--no-deb) BUILD_DEB=0 ;;
|
||||||
-h|--help) sed -n '2,16p' "$0"; exit 0 ;;
|
-h|--help) sed -n '2,17p' "$0"; exit 0 ;;
|
||||||
*) echo "Argument inconnu : $arg" >&2; exit 1 ;;
|
*) echo "Argument inconnu : $arg" >&2; exit 1 ;;
|
||||||
esac
|
esac
|
||||||
done
|
done
|
||||||
@@ -116,22 +118,27 @@ cp -f "$PROJECT_DIR/src-tauri/icons/128x128.png" "$SCRIPT_DIR/icon.png"
|
|||||||
echo ">> Construction du Flatpak…"
|
echo ">> Construction du Flatpak…"
|
||||||
rm -rf "$BUILD_DIR"
|
rm -rf "$BUILD_DIR"
|
||||||
FB_ARGS=(--force-clean --user --install-deps-from=flathub --repo="$REPO_DIR")
|
FB_ARGS=(--force-clean --user --install-deps-from=flathub --repo="$REPO_DIR")
|
||||||
if [[ "$DO_BUNDLE" -eq 0 ]]; then
|
if [[ "$DO_INSTALL" -eq 1 ]]; then
|
||||||
FB_ARGS+=(--install)
|
FB_ARGS+=(--install)
|
||||||
fi
|
fi
|
||||||
"${FLATPAK_BUILDER[@]}" "${FB_ARGS[@]}" "$BUILD_DIR" "$MANIFEST"
|
"${FLATPAK_BUILDER[@]}" "${FB_ARGS[@]}" "$BUILD_DIR" "$MANIFEST"
|
||||||
|
|
||||||
# --- 3. Export d'un fichier .flatpak (optionnel) -----------------------------
|
# --- 3. Export du fichier .flatpak (toujours) --------------------------------
|
||||||
if [[ "$DO_BUNDLE" -eq 1 ]]; then
|
# Le bundle autonome est systématiquement exporté à côté du manifeste.
|
||||||
OUT="$SCRIPT_DIR/Pena.flatpak"
|
OUT="$SCRIPT_DIR/pena.flatpak"
|
||||||
echo ">> Export du bundle : $OUT"
|
echo ">> Export du bundle : $OUT"
|
||||||
flatpak build-bundle "$REPO_DIR" "$OUT" "$APP_ID" \
|
flatpak build-bundle "$REPO_DIR" "$OUT" "$APP_ID" \
|
||||||
--runtime-repo=https://flathub.org/repo/flathub.flatpakrepo
|
--runtime-repo=https://flathub.org/repo/flathub.flatpakrepo
|
||||||
|
|
||||||
echo ">> Nettoyage du dépôt OSTree temporaire…"
|
echo ">> Nettoyage du dépôt OSTree temporaire…"
|
||||||
rm -rf "$REPO_DIR"
|
rm -rf "$REPO_DIR"
|
||||||
echo ">> Installer avec : flatpak install --user $OUT"
|
|
||||||
|
if [[ "$DO_INSTALL" -eq 1 ]]; then
|
||||||
|
echo ">> Pena $VERSION installé (--user) et bundle exporté : $OUT"
|
||||||
|
echo ">> Lancer avec : flatpak run $APP_ID"
|
||||||
else
|
else
|
||||||
echo ">> Pena $VERSION installé. Lancer avec : flatpak run $APP_ID"
|
echo ">> Bundle exporté : $OUT"
|
||||||
|
echo ">> Installer avec : flatpak install --user $OUT"
|
||||||
fi
|
fi
|
||||||
|
|
||||||
echo ">> Terminé."
|
echo ">> Terminé."
|
||||||
|
|||||||
@@ -19,6 +19,7 @@
|
|||||||
</categories>
|
</categories>
|
||||||
<content_rating type="oars-1.1"/>
|
<content_rating type="oars-1.1"/>
|
||||||
<releases>
|
<releases>
|
||||||
|
<release version="0.1.2" date="2026-07-05"/>
|
||||||
<release version="0.1.0" date="2026-06-23"/>
|
<release version="0.1.0" date="2026-06-23"/>
|
||||||
</releases>
|
</releases>
|
||||||
</component>
|
</component>
|
||||||
|
|||||||
@@ -21,6 +21,8 @@ modules:
|
|||||||
path: pena.deb
|
path: pena.deb
|
||||||
- type: file
|
- type: file
|
||||||
path: com.pena.app.metainfo.xml
|
path: com.pena.app.metainfo.xml
|
||||||
|
- type: file
|
||||||
|
path: icon.png
|
||||||
build-commands:
|
build-commands:
|
||||||
- |
|
- |
|
||||||
set -eux
|
set -eux
|
||||||
@@ -40,9 +42,8 @@ modules:
|
|||||||
-e 's/^Icon=.*/Icon=com.pena.app/' \
|
-e 's/^Icon=.*/Icon=com.pena.app/' \
|
||||||
/app/share/applications/com.pena.app.desktop
|
/app/share/applications/com.pena.app.desktop
|
||||||
|
|
||||||
# Icône : on prend la plus grande disponible
|
# Icône (128x128) fournie séparément à côté du manifeste.
|
||||||
icon="$(find usr/share/icons -name '*.png' | sort | tail -n1)"
|
install -Dm644 icon.png /app/share/icons/hicolor/128x128/apps/com.pena.app.png
|
||||||
install -Dm644 "$icon" /app/share/icons/hicolor/128x128/apps/com.pena.app.png
|
|
||||||
|
|
||||||
# Métadonnées AppStream
|
# Métadonnées AppStream
|
||||||
install -Dm644 com.pena.app.metainfo.xml /app/share/metainfo/com.pena.app.metainfo.xml
|
install -Dm644 com.pena.app.metainfo.xml /app/share/metainfo/com.pena.app.metainfo.xml
|
||||||
|
|||||||
|
After Width: | Height: | Size: 6.9 KiB |
@@ -2445,7 +2445,7 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "pena-taury"
|
name = "pena-taury"
|
||||||
version = "0.1.0"
|
version = "0.1.2"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"comrak",
|
"comrak",
|
||||||
"notify",
|
"notify",
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
[package]
|
[package]
|
||||||
name = "pena-taury"
|
name = "pena-taury"
|
||||||
version = "0.1.0"
|
version = "0.1.2"
|
||||||
edition = "2021"
|
edition = "2021"
|
||||||
|
|
||||||
[lib]
|
[lib]
|
||||||
|
|||||||
|
After Width: | Height: | Size: 13 KiB |
|
After Width: | Height: | Size: 32 KiB |
|
After Width: | Height: | Size: 1.8 KiB |
|
After Width: | Height: | Size: 4.9 KiB |
|
After Width: | Height: | Size: 10 KiB |
|
After Width: | Height: | Size: 15 KiB |
|
After Width: | Height: | Size: 16 KiB |
|
After Width: | Height: | Size: 38 KiB |
|
After Width: | Height: | Size: 1.6 KiB |
|
After Width: | Height: | Size: 42 KiB |
|
After Width: | Height: | Size: 2.9 KiB |
|
After Width: | Height: | Size: 5.7 KiB |
|
After Width: | Height: | Size: 7.8 KiB |
|
After Width: | Height: | Size: 3.5 KiB |
@@ -0,0 +1,5 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<adaptive-icon xmlns:android="http://schemas.android.com/apk/res/android">
|
||||||
|
<foreground android:drawable="@mipmap/ic_launcher_foreground"/>
|
||||||
|
<background android:drawable="@color/ic_launcher_background"/>
|
||||||
|
</adaptive-icon>
|
||||||
|
After Width: | Height: | Size: 2.8 KiB |
|
After Width: | Height: | Size: 18 KiB |
|
After Width: | Height: | Size: 2.9 KiB |
|
After Width: | Height: | Size: 2.6 KiB |
|
After Width: | Height: | Size: 10 KiB |
|
After Width: | Height: | Size: 2.8 KiB |
|
After Width: | Height: | Size: 7.3 KiB |
|
After Width: | Height: | Size: 26 KiB |
|
After Width: | Height: | Size: 7.9 KiB |
|
After Width: | Height: | Size: 13 KiB |
|
After Width: | Height: | Size: 45 KiB |
|
After Width: | Height: | Size: 14 KiB |
|
After Width: | Height: | Size: 20 KiB |
|
After Width: | Height: | Size: 69 KiB |
|
After Width: | Height: | Size: 21 KiB |
@@ -0,0 +1,4 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<resources>
|
||||||
|
<color name="ic_launcher_background">#fff</color>
|
||||||
|
</resources>
|
||||||
|
After Width: | Height: | Size: 44 KiB |
|
Before Width: | Height: | Size: 105 B After Width: | Height: | Size: 86 KiB |
|
After Width: | Height: | Size: 928 B |
|
After Width: | Height: | Size: 2.5 KiB |
|
After Width: | Height: | Size: 2.5 KiB |
|
After Width: | Height: | Size: 4.4 KiB |
|
After Width: | Height: | Size: 1.5 KiB |
|
After Width: | Height: | Size: 4.2 KiB |
|
After Width: | Height: | Size: 4.2 KiB |
|
After Width: | Height: | Size: 7.6 KiB |
|
After Width: | Height: | Size: 2.5 KiB |
|
After Width: | Height: | Size: 6.7 KiB |
|
After Width: | Height: | Size: 6.7 KiB |
|
After Width: | Height: | Size: 12 KiB |
|
After Width: | Height: | Size: 253 KiB |
|
After Width: | Height: | Size: 12 KiB |
|
After Width: | Height: | Size: 20 KiB |
|
After Width: | Height: | Size: 6.2 KiB |
|
After Width: | Height: | Size: 16 KiB |
|
After Width: | Height: | Size: 18 KiB |
@@ -1,7 +1,7 @@
|
|||||||
{
|
{
|
||||||
"$schema": "https://schema.tauri.app/config/2",
|
"$schema": "https://schema.tauri.app/config/2",
|
||||||
"productName": "Pena",
|
"productName": "Pena",
|
||||||
"version": "0.1.0",
|
"version": "0.1.2",
|
||||||
"identifier": "com.pena.app",
|
"identifier": "com.pena.app",
|
||||||
"build": {
|
"build": {
|
||||||
"frontendDist": "../src"
|
"frontendDist": "../src"
|
||||||
@@ -24,6 +24,12 @@
|
|||||||
"bundle": {
|
"bundle": {
|
||||||
"active": false,
|
"active": false,
|
||||||
"targets": "all",
|
"targets": "all",
|
||||||
"icon": []
|
"icon": [
|
||||||
|
"icons/32x32.png",
|
||||||
|
"icons/128x128.png",
|
||||||
|
"icons/128x128@2x.png",
|
||||||
|
"icons/icon.icns",
|
||||||
|
"icons/icon.ico"
|
||||||
|
]
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
|
After Width: | Height: | Size: 9.4 KiB |
@@ -22,6 +22,7 @@
|
|||||||
<div id="app-content">
|
<div id="app-content">
|
||||||
|
|
||||||
<div id="view-home">
|
<div id="view-home">
|
||||||
|
<img class="home-logo" src="assets/icon.png" alt="Pena" />
|
||||||
<h1 class="home-title">Pena</h1>
|
<h1 class="home-title">Pena</h1>
|
||||||
<div class="home-buttons">
|
<div class="home-buttons">
|
||||||
<button id="btn-open-file">Ouvrir un fichier Markdown</button>
|
<button id="btn-open-file">Ouvrir un fichier Markdown</button>
|
||||||
@@ -47,6 +48,7 @@
|
|||||||
</button>
|
</button>
|
||||||
<button id="btn-back" class="btn-back">← Accueil</button>
|
<button id="btn-back" class="btn-back">← Accueil</button>
|
||||||
</div>
|
</div>
|
||||||
|
<div id="sidebar-resizer" class="sidebar__resizer" title="Redimensionner"></div>
|
||||||
</div>
|
</div>
|
||||||
<div id="content" class="content">
|
<div id="content" class="content">
|
||||||
<!-- contenu généré par JS -->
|
<!-- contenu généré par JS -->
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
import { showHome, openPath } from './router.js';
|
import { showHome, openPath, initWatcher } from './router.js';
|
||||||
import { initCssModal } from './ui/css-modal.js';
|
import { initCssModal } from './ui/css-modal.js';
|
||||||
|
import { initSidebarResize } from './ui/sidebar-resize.js';
|
||||||
|
|
||||||
const win = window.__TAURI__.window.getCurrentWindow();
|
const win = window.__TAURI__.window.getCurrentWindow();
|
||||||
|
|
||||||
@@ -33,4 +34,6 @@ document.getElementById('btn-open-dir').addEventListener('click', async () => {
|
|||||||
document.getElementById('btn-back').addEventListener('click', showHome);
|
document.getElementById('btn-back').addEventListener('click', showHome);
|
||||||
|
|
||||||
await initCssModal();
|
await initCssModal();
|
||||||
|
initSidebarResize();
|
||||||
|
await initWatcher();
|
||||||
showHome();
|
showHome();
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
import { appState } from './state/app-state.js';
|
import { appState } from './state/app-state.js';
|
||||||
import { listMdFiles } from './services/files.js';
|
import { listMdFiles } from './services/files.js';
|
||||||
|
import { startWatch, stopWatch, onFileChanged } from './services/watcher.js';
|
||||||
import { renderSidebar } from './ui/sidebar.js';
|
import { renderSidebar } from './ui/sidebar.js';
|
||||||
import { loadPage } from './ui/reader.js';
|
import { loadPage } from './ui/reader.js';
|
||||||
import { saveRecent, renderRecents } from './ui/home.js';
|
import { saveRecent, renderRecents } from './ui/home.js';
|
||||||
@@ -11,9 +12,15 @@ const content = document.querySelector('#content');
|
|||||||
const win = window.__TAURI__.window.getCurrentWindow();
|
const win = window.__TAURI__.window.getCurrentWindow();
|
||||||
const titlebarTitle = document.getElementById('titlebar-title');
|
const titlebarTitle = document.getElementById('titlebar-title');
|
||||||
|
|
||||||
|
const navigate = filePath => loadPage(filePath, appState.currentMode, sidebarEl);
|
||||||
|
|
||||||
export function showHome() {
|
export function showHome() {
|
||||||
|
stopWatch();
|
||||||
appState.currentPath = null;
|
appState.currentPath = null;
|
||||||
appState.currentMode = null;
|
appState.currentMode = null;
|
||||||
|
appState.baseDir = null;
|
||||||
|
appState.currentFile = null;
|
||||||
|
appState.files = [];
|
||||||
sidebarEl.innerHTML = '';
|
sidebarEl.innerHTML = '';
|
||||||
win.setTitle('Pena — Markdown Viewer');
|
win.setTitle('Pena — Markdown Viewer');
|
||||||
titlebarTitle.textContent = 'Pena — Markdown Viewer';
|
titlebarTitle.textContent = 'Pena — Markdown Viewer';
|
||||||
@@ -38,15 +45,21 @@ export async function openPath(path, mode) {
|
|||||||
const parentDir = path.split(sep).slice(0, -1).join(sep);
|
const parentDir = path.split(sep).slice(0, -1).join(sep);
|
||||||
try {
|
try {
|
||||||
const files = await listMdFiles(parentDir);
|
const files = await listMdFiles(parentDir);
|
||||||
|
appState.baseDir = parentDir;
|
||||||
|
appState.files = files;
|
||||||
sidebarEl.classList.remove('hidden');
|
sidebarEl.classList.remove('hidden');
|
||||||
content.style.marginLeft = '';
|
content.style.marginLeft = '';
|
||||||
renderSidebar(parentDir, files, path, filePath => loadPage(filePath, appState.currentMode, sidebarEl));
|
renderSidebar(parentDir, files, path, navigate);
|
||||||
} catch {
|
} catch {
|
||||||
|
// Le dossier parent est illisible : on surveille au moins le fichier ouvert.
|
||||||
|
appState.baseDir = path;
|
||||||
|
appState.files = [];
|
||||||
sidebarEl.innerHTML = '';
|
sidebarEl.innerHTML = '';
|
||||||
sidebarEl.classList.add('hidden');
|
sidebarEl.classList.add('hidden');
|
||||||
content.style.marginLeft = '0';
|
content.style.marginLeft = '0';
|
||||||
}
|
}
|
||||||
await loadPage(path, appState.currentMode, sidebarEl);
|
await loadPage(path, appState.currentMode, sidebarEl);
|
||||||
|
startWatch(appState.baseDir);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -56,6 +69,8 @@ export async function openPath(path, mode) {
|
|||||||
|
|
||||||
try {
|
try {
|
||||||
const files = await listMdFiles(path);
|
const files = await listMdFiles(path);
|
||||||
|
appState.baseDir = path;
|
||||||
|
appState.files = files;
|
||||||
showReader();
|
showReader();
|
||||||
|
|
||||||
const sep = path.includes('\\') ? '\\' : '/';
|
const sep = path.includes('\\') ? '\\' : '/';
|
||||||
@@ -65,10 +80,48 @@ export async function openPath(path, mode) {
|
|||||||
});
|
});
|
||||||
|
|
||||||
const firstFile = home ?? files[0];
|
const firstFile = home ?? files[0];
|
||||||
renderSidebar(path, files, firstFile, filePath => loadPage(filePath, appState.currentMode, sidebarEl));
|
renderSidebar(path, files, firstFile, navigate);
|
||||||
await loadPage(firstFile, appState.currentMode, sidebarEl);
|
await loadPage(firstFile, appState.currentMode, sidebarEl);
|
||||||
|
startWatch(path);
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
showReader();
|
showReader();
|
||||||
content.innerHTML = `<p class="error">Impossible d'ouvrir le dossier : ${err}</p>`;
|
content.innerHTML = `<p class="error">Impossible d'ouvrir le dossier : ${err}</p>`;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Compare deux listes de fichiers indépendamment de l'ordre.
|
||||||
|
function sameFiles(a, b) {
|
||||||
|
if (a.length !== b.length) return false;
|
||||||
|
const key = arr => arr.slice().sort().join('\n');
|
||||||
|
return key(a) === key(b);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Réaction à un changement filesystem signalé par le backend (événement débouncé,
|
||||||
|
// filtré sur les fichiers .md).
|
||||||
|
async function handleFileChanged(changedPath) {
|
||||||
|
if (!appState.baseDir || !appState.currentMode) return;
|
||||||
|
|
||||||
|
// Rafraîchir la sidebar uniquement si l'arborescence a changé (ajout/suppression),
|
||||||
|
// pour ne pas replier les dossiers ouverts à chaque simple modification de contenu.
|
||||||
|
try {
|
||||||
|
const files = await listMdFiles(appState.baseDir);
|
||||||
|
if (!sameFiles(files, appState.files)) {
|
||||||
|
appState.files = files;
|
||||||
|
renderSidebar(appState.baseDir, files, appState.currentFile, navigate);
|
||||||
|
}
|
||||||
|
} catch {
|
||||||
|
// baseDir supprimé/illisible : on garde la sidebar en l'état.
|
||||||
|
}
|
||||||
|
|
||||||
|
// Recharger le document affiché si c'est lui qui vient d'être modifié.
|
||||||
|
if (changedPath === appState.currentFile) {
|
||||||
|
await loadPage(appState.currentFile, appState.currentMode, sidebarEl);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// À appeler une fois au démarrage : enregistre le listener global de changements.
|
||||||
|
export function initWatcher() {
|
||||||
|
return onFileChanged(event => {
|
||||||
|
handleFileChanged(event.payload.path);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|||||||
@@ -1 +1,12 @@
|
|||||||
export const appState = { currentPath: null, currentMode: null };
|
export const appState = {
|
||||||
|
currentPath: null,
|
||||||
|
currentMode: null,
|
||||||
|
// Dossier réellement surveillé (racine de la sidebar) : le dossier ouvert en
|
||||||
|
// mode « dir », ou le dossier parent du fichier ouvert en mode « file ».
|
||||||
|
baseDir: null,
|
||||||
|
// Fichier actuellement affiché dans le lecteur.
|
||||||
|
currentFile: null,
|
||||||
|
// Dernière liste de fichiers .md connue de `baseDir`, pour détecter les
|
||||||
|
// ajouts/suppressions et ne rafraîchir la sidebar que si l'arborescence change.
|
||||||
|
files: [],
|
||||||
|
};
|
||||||
|
|||||||
@@ -1,4 +1,5 @@
|
|||||||
import { convertFile } from '../services/markdown.js';
|
import { convertFile } from '../services/markdown.js';
|
||||||
|
import { appState } from '../state/app-state.js';
|
||||||
|
|
||||||
const win = window.__TAURI__.window.getCurrentWindow();
|
const win = window.__TAURI__.window.getCurrentWindow();
|
||||||
const titlebarTitle = document.getElementById('titlebar-title');
|
const titlebarTitle = document.getElementById('titlebar-title');
|
||||||
@@ -69,6 +70,7 @@ function addCopyButtons() {
|
|||||||
export async function loadPage(filePath, mode, sidebarEl) {
|
export async function loadPage(filePath, mode, sidebarEl) {
|
||||||
try {
|
try {
|
||||||
const html = await convertFile(filePath);
|
const html = await convertFile(filePath);
|
||||||
|
appState.currentFile = filePath;
|
||||||
content.innerHTML = html;
|
content.innerHTML = html;
|
||||||
addCopyButtons();
|
addCopyButtons();
|
||||||
|
|
||||||
|
|||||||
@@ -0,0 +1,49 @@
|
|||||||
|
const STORAGE_KEY = 'pena.sidebarWidth';
|
||||||
|
const MIN_WIDTH = 180;
|
||||||
|
const MAX_WIDTH = 520;
|
||||||
|
|
||||||
|
function clamp(width) {
|
||||||
|
return Math.min(MAX_WIDTH, Math.max(MIN_WIDTH, width));
|
||||||
|
}
|
||||||
|
|
||||||
|
function applyWidth(width) {
|
||||||
|
document.documentElement.style.setProperty('--sidebar-width', `${width}px`);
|
||||||
|
}
|
||||||
|
|
||||||
|
export function initSidebarResize() {
|
||||||
|
const handle = document.getElementById('sidebar-resizer');
|
||||||
|
if (!handle) return;
|
||||||
|
|
||||||
|
const stored = parseInt(localStorage.getItem(STORAGE_KEY), 10);
|
||||||
|
if (!Number.isNaN(stored)) applyWidth(clamp(stored));
|
||||||
|
|
||||||
|
let dragging = false;
|
||||||
|
|
||||||
|
const onMove = (e) => {
|
||||||
|
if (!dragging) return;
|
||||||
|
applyWidth(clamp(e.clientX));
|
||||||
|
};
|
||||||
|
|
||||||
|
const onUp = () => {
|
||||||
|
if (!dragging) return;
|
||||||
|
dragging = false;
|
||||||
|
handle.classList.remove('is-dragging');
|
||||||
|
document.body.classList.remove('is-resizing-sidebar');
|
||||||
|
const width = parseInt(
|
||||||
|
getComputedStyle(document.documentElement).getPropertyValue('--sidebar-width'),
|
||||||
|
10,
|
||||||
|
);
|
||||||
|
if (!Number.isNaN(width)) localStorage.setItem(STORAGE_KEY, String(width));
|
||||||
|
window.removeEventListener('mousemove', onMove);
|
||||||
|
window.removeEventListener('mouseup', onUp);
|
||||||
|
};
|
||||||
|
|
||||||
|
handle.addEventListener('mousedown', (e) => {
|
||||||
|
e.preventDefault();
|
||||||
|
dragging = true;
|
||||||
|
handle.classList.add('is-dragging');
|
||||||
|
document.body.classList.add('is-resizing-sidebar');
|
||||||
|
window.addEventListener('mousemove', onMove);
|
||||||
|
window.addEventListener('mouseup', onUp);
|
||||||
|
});
|
||||||
|
}
|
||||||