diff --git a/src/index.html b/src/index.html
index f928ac8..0cfaea6 100644
--- a/src/index.html
+++ b/src/index.html
@@ -11,6 +11,15 @@
+
Pena
diff --git a/src/main.js b/src/main.js
index a73f1ee..78f6782 100644
--- a/src/main.js
+++ b/src/main.js
@@ -1,6 +1,21 @@
let currentPath = null;
let currentMode = null; // 'file' | 'dir'
+const titlebarTitle = document.getElementById('titlebar-title');
+const win = window.__TAURI__.window.getCurrentWindow();
+
+document.getElementById('titlebar').addEventListener('mousedown', (e) => {
+ if (e.target.closest('.titlebar-controls')) return;
+ if (e.buttons === 1) win.startDragging();
+});
+
+document.getElementById('titlebar-minimize').addEventListener('click', () => win.minimize());
+document.getElementById('titlebar-maximize').addEventListener('click', async () => {
+ if (await win.isMaximized()) win.unmaximize();
+ else win.maximize();
+});
+document.getElementById('titlebar-close').addEventListener('click', () => win.close());
+
const viewHome = document.getElementById('view-home');
const viewReader = document.getElementById('view-reader');
const sidebar = document.querySelector('#sidebar');
@@ -165,9 +180,10 @@ async function loadPage(filePath) {
const basename = filePath.split('/').pop().split('\\').pop();
const title = basename.replace(/\.md$/i, '');
- await window.__TAURI__.window.getCurrentWindow().setTitle(title);
+ await win.setTitle(title);
+ titlebarTitle.textContent = title;
- if (currentMode === 'dir') {
+ if (currentMode === 'dir' || currentMode === 'file') {
sidebar.querySelectorAll('a').forEach(a => {
a.classList.toggle('active', a.dataset.path === filePath);
});
@@ -191,10 +207,19 @@ async function openPath(path, mode) {
saveRecent(path, mode);
if (mode === 'file') {
- sidebar.innerHTML = '';
- sidebar.classList.add('hidden');
- content.style.marginLeft = '0';
showReader();
+ const sep = path.includes('\\') ? '\\' : '/';
+ const parentDir = path.split(sep).slice(0, -1).join(sep);
+ try {
+ const files = await window.__TAURI__.core.invoke('list_md_files', { dir: parentDir });
+ sidebar.classList.remove('hidden');
+ content.style.marginLeft = '';
+ renderSidebar(parentDir, files, path);
+ } catch {
+ sidebar.innerHTML = '';
+ sidebar.classList.add('hidden');
+ content.style.marginLeft = '0';
+ }
await loadPage(path);
return;
}
@@ -243,5 +268,54 @@ document.getElementById('btn-back').addEventListener('click', () => {
currentPath = null;
currentMode = null;
sidebar.innerHTML = '';
+ win.setTitle('Pena — Markdown Viewer');
+ titlebarTitle.textContent = 'Pena — Markdown Viewer';
showHome();
});
+
+// ── CSS personnalisé ──
+const CSS_STORAGE_KEY = 'pena_custom_css';
+
+function applyCustomCss(css) {
+ let styleEl = document.getElementById('pena-custom-style');
+ if (!styleEl) {
+ styleEl = document.createElement('style');
+ styleEl.id = 'pena-custom-style';
+ document.head.appendChild(styleEl);
+ }
+ styleEl.textContent = css;
+}
+
+function loadCustomCss() {
+ return localStorage.getItem(CSS_STORAGE_KEY) ?? '';
+}
+
+const savedCss = loadCustomCss();
+if (savedCss) applyCustomCss(savedCss);
+
+const btnCustomizeCss = document.getElementById('btn-customize-css');
+const cssEditorPanel = document.getElementById('css-editor-panel');
+const cssEditor = document.getElementById('css-editor');
+
+cssEditor.value = loadCustomCss();
+
+btnCustomizeCss.addEventListener('click', () => {
+ cssEditorPanel.classList.toggle('hidden');
+});
+
+document.getElementById('btn-css-close').addEventListener('click', () => {
+ cssEditorPanel.classList.add('hidden');
+});
+
+document.getElementById('btn-css-apply').addEventListener('click', () => {
+ const css = cssEditor.value.trim();
+ applyCustomCss(css);
+ localStorage.setItem(CSS_STORAGE_KEY, css);
+ cssEditorPanel.classList.add('hidden');
+});
+
+document.getElementById('btn-css-reset').addEventListener('click', () => {
+ cssEditor.value = '';
+ applyCustomCss('');
+ localStorage.removeItem(CSS_STORAGE_KEY);
+});
diff --git a/src/style.css b/src/style.css
index e0a6304..4102cf1 100644
--- a/src/style.css
+++ b/src/style.css
@@ -11,6 +11,64 @@ body {
overflow-x: hidden;
}
+/* ── Titlebar ── */
+#titlebar {
+ position: fixed;
+ top: 0;
+ left: 0;
+ right: 0;
+ height: 36px;
+ background: #1a1b2e;
+ display: flex;
+ align-items: center;
+ justify-content: center;
+ z-index: 200;
+ user-select: none;
+ -webkit-user-select: none;
+}
+
+#titlebar-title {
+ color: rgba(255,255,255,0.5);
+ font-size: 12px;
+ font-weight: 500;
+ letter-spacing: 0.02em;
+ pointer-events: none;
+}
+
+.titlebar-controls {
+ position: absolute;
+ right: 0;
+ top: 0;
+ height: 36px;
+ display: flex;
+ align-items: center;
+}
+
+.titlebar-controls button {
+ width: 46px;
+ height: 36px;
+ background: transparent;
+ border: none;
+ color: rgba(255,255,255,0.45);
+ font-size: 13px;
+ cursor: pointer;
+ display: flex;
+ align-items: center;
+ justify-content: center;
+ transition: background 0.15s, color 0.15s;
+ font-family: inherit;
+}
+
+.titlebar-controls button:hover {
+ background: rgba(255,255,255,0.08);
+ color: rgba(255,255,255,0.9);
+}
+
+#titlebar-close:hover {
+ background: #e81123 !important;
+ color: #fff !important;
+}
+
/* ── Utility ── */
.hidden { display: none !important; }
@@ -21,6 +79,7 @@ body {
align-items: center;
justify-content: center;
height: 100vh;
+ padding-top: 36px;
background: #1a1b2e;
}
@@ -137,10 +196,10 @@ body {
/* ── Sidebar ── */
.sidebar {
position: fixed;
- top: 0;
+ top: 36px;
left: 0;
width: 264px;
- height: 100vh;
+ height: calc(100vh - 36px);
background: #1a1b2e;
display: flex;
flex-direction: column;
@@ -148,7 +207,7 @@ body {
overflow: hidden;
}
.sidebar__title-block {
- margin: 48px 24px 8px;
+ margin: 32px 24px 8px;
flex-shrink: 0;
}
.sidebar__title-block a {
@@ -320,7 +379,10 @@ body {
/* ── Content ── */
.content {
margin-left: 264px;
- padding: 48px 72px 96px;
+ padding-top: 84px;
+ padding-right: 72px;
+ padding-bottom: 96px;
+ padding-left: 72px;
max-width: 1080px;
min-height: 100vh;
background: #fff;
@@ -395,12 +457,131 @@ body {
}
.content ul li code, .content ol li code { font-weight: 700; }
+/* ── Customize CSS button ── */
+.btn-customize-css {
+ position: fixed;
+ bottom: 60px;
+ left: 12px;
+ width: 240px;
+ z-index: 100;
+ background: transparent;
+ color: rgba(255,255,255,0.7);
+ border: 1px solid rgba(255,255,255,0.15);
+ border-radius: 8px;
+ padding: 8px 16px;
+ font-family: 'Poppins', sans-serif;
+ font-size: 13px;
+ font-weight: 500;
+ cursor: pointer;
+ text-align: left;
+ display: flex;
+ align-items: center;
+ gap: 8px;
+ transition: color 0.2s, border-color 0.2s, background 0.2s;
+}
+.btn-customize-css:hover {
+ color: #fff;
+ border-color: rgba(255,255,255,0.35);
+ background: rgba(255,255,255,0.06);
+}
+.btn-customize-css__icon {
+ font-size: 15px;
+ opacity: 0.8;
+}
+
+/* ── CSS editor panel ── */
+.css-editor-panel {
+ position: fixed;
+ bottom: 120px;
+ left: 12px;
+ width: 240px;
+ background: #12132a;
+ border: 1px solid rgba(255,255,255,0.15);
+ border-radius: 10px;
+ z-index: 101;
+ display: flex;
+ flex-direction: column;
+ box-shadow: 0 8px 32px rgba(0,0,0,0.5);
+ overflow: hidden;
+}
+.css-editor-panel__header {
+ display: flex;
+ align-items: center;
+ justify-content: space-between;
+ padding: 10px 14px;
+ border-bottom: 1px solid rgba(255,255,255,0.08);
+ color: rgba(255,255,255,0.7);
+ font-size: 12px;
+ font-weight: 600;
+ text-transform: uppercase;
+ letter-spacing: 0.06em;
+}
+.css-editor-panel__close {
+ background: transparent;
+ border: none;
+ color: rgba(255,255,255,0.4);
+ font-size: 13px;
+ cursor: pointer;
+ padding: 2px 4px;
+ border-radius: 4px;
+ font-family: inherit;
+ transition: color 0.15s, background 0.15s;
+}
+.css-editor-panel__close:hover {
+ color: #fff;
+ background: rgba(255,255,255,0.08);
+}
+.css-editor__textarea {
+ width: 100%;
+ height: 180px;
+ background: #0e0f24;
+ border: none;
+ color: rgba(255,255,255,0.8);
+ font-family: 'Roboto Mono', monospace;
+ font-size: 11px;
+ line-height: 1.6;
+ padding: 12px;
+ resize: none;
+ outline: none;
+}
+.css-editor__textarea::placeholder {
+ color: rgba(255,255,255,0.2);
+}
+.css-editor-panel__footer {
+ display: flex;
+ gap: 8px;
+ padding: 10px 12px;
+ border-top: 1px solid rgba(255,255,255,0.08);
+}
+.css-editor-panel__btn {
+ flex: 1;
+ padding: 6px 10px;
+ border: none;
+ border-radius: 6px;
+ font-family: 'Poppins', sans-serif;
+ font-size: 12px;
+ font-weight: 600;
+ cursor: pointer;
+ transition: background 0.15s;
+}
+.css-editor-panel__btn--primary {
+ background: #ff5577;
+ color: #fff;
+}
+.css-editor-panel__btn--primary:hover { background: #ff3355; }
+.css-editor-panel__btn--secondary {
+ background: rgba(255,255,255,0.08);
+ color: rgba(255,255,255,0.7);
+}
+.css-editor-panel__btn--secondary:hover { background: rgba(255,255,255,0.14); }
+
/* ── Back button ── */
.btn-back {
position: fixed;
bottom: 24px;
left: 0;
width: 264px;
+ z-index: 98;
background: transparent;
color: rgba(255,255,255,0.45);
border: none;
@@ -421,8 +602,8 @@ body {
left: -300px;
transition: left 0.2s cubic-bezier(0.09, 0.46, 0.45, 0.94);
}
- .content { margin-left: 0; padding: 32px 24px 64px; }
+ .content { margin-left: 0; padding: 68px 24px 64px; }
}
@media screen and (max-width: 540px) {
- .content { padding: 24px 16px 48px; }
+ .content { padding: 68px 16px 48px; }
}