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
12 changes: 11 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -77,8 +77,17 @@ Sağ üstteki **Export** düğmesiyle mevcut sekme içeriği şu biçimlerde dı

### Çoklu Sekme
- `+` düğmesiyle yeni dosya/sekme oluşturma
- Sekme adına çift tıklayarak veya sağ tık menüsünden yeniden adlandırma
- Sağ tık menüsünden notebook kopyalama
- Sekmeleri sürükle-bırak ile yeniden sıralama
- Kapatılan notebook'u 8 saniye içinde **Geri Al** ile geri getirme
- Sekmeler `localStorage`'da kalıcı olarak saklanır
- Sekme adı çift tıkla düzenlenebilir

### Notebook Arama
- Üst bardaki **Ara / Search** düğmesi veya `Ctrl/Cmd + K` ile tüm notebook'larda arama
- Dosya adı ve satır içeriği birlikte aranır
- Sonuçlarda notebook adı, satır numarası ve içerik önizlemesi gösterilir
- Sonuca tıklanınca ilgili notebook açılır ve eşleşen satıra odaklanılır

### Ekle Modalı
`+` FAB (sağ alt) veya klavye kısayoluyla açılır. Şablonlu form üzerinden şunlar eklenebilir:
Expand Down Expand Up @@ -132,6 +141,7 @@ Bu kontrol, build çıktısında uzak script/style/module bağlantısı kalmadı
|---------|-------|
| `Ctrl` + `+` | Yakınlaştır |
| `Ctrl` + `-` | Uzaklaştır |
| `Ctrl/Cmd` + `K` | Tüm notebook'larda ara |

---

Expand Down
184 changes: 182 additions & 2 deletions index.html
Original file line number Diff line number Diff line change
Expand Up @@ -66,7 +66,7 @@
border-radius: 6px;
padding: 2px;
}
#export-btn, #backup-btn, #examples-btn, #info-btn {
#export-btn, #backup-btn, #examples-btn, #search-btn, #info-btn {
padding: 4px 10px;
border: 1px solid #ced4da;
background: #fff;
Expand All @@ -82,7 +82,7 @@
gap: 4px;
white-space: nowrap;
}
#export-btn:hover, #backup-btn:hover, #examples-btn:hover, #info-btn:hover {
#export-btn:hover, #backup-btn:hover, #examples-btn:hover, #search-btn:hover, #info-btn:hover {
background: #f1f3f5;
border-color: #1A71C2;
color: #1A71C2;
Expand Down Expand Up @@ -268,6 +268,77 @@
}
#new-tab-btn:hover { background: #f1f3f5; color: #495057; }

.file-tab.dragging {
opacity: 0.45;
}
.file-tab.drag-over {
border-left: 3px solid #1971c2;
padding-left: 11px;
}
.tab-context-menu {
position: fixed;
min-width: 170px;
padding: 5px;
border: 1px solid #dee2e6;
border-radius: 7px;
background: #fff;
box-shadow: 0 10px 28px rgba(0,0,0,0.14);
z-index: 1600;
display: none;
}
.tab-context-menu.active { display: block; }
.tab-context-menu button {
width: 100%;
display: block;
padding: 7px 9px;
border: 0;
border-radius: 5px;
background: transparent;
color: #343a40;
text-align: left;
cursor: pointer;
font: inherit;
font-size: 12px;
}
.tab-context-menu button:hover {
background: #f1f3f5;
color: #1971c2;
}
.undo-toast {
position: fixed;
left: 50%;
bottom: 42px;
transform: translate(-50%, 12px);
display: flex;
align-items: center;
gap: 12px;
max-width: min(520px, calc(100vw - 28px));
padding: 9px 12px;
border-radius: 8px;
background: #343a40;
color: #fff;
box-shadow: 0 8px 24px rgba(0,0,0,0.2);
z-index: 1700;
font-size: 12px;
opacity: 0;
pointer-events: none;
transition: opacity .16s ease, transform .16s ease;
}
.undo-toast.active {
opacity: 1;
transform: translate(-50%, 0);
pointer-events: auto;
}
.undo-toast button {
border: 0;
background: transparent;
color: #74c0fc;
font: inherit;
font-weight: 700;
cursor: pointer;
padding: 2px 4px;
}

/* ---- Main ---- */
#main { display: flex; flex: 1; overflow: hidden; }

Expand Down Expand Up @@ -843,6 +914,88 @@
}
#modal-confirm:hover, #export-confirm:hover { background: #1864ab; }

.search-modal {
width: 620px;
max-width: 92vw;
padding: 0;
overflow: hidden;
}
.search-modal-head {
padding: 16px 18px 12px;
border-bottom: 1px solid #e9ecef;
}
#notebook-search-input {
width: 100%;
box-sizing: border-box;
padding: 9px 11px;
border: 1px solid #ced4da;
border-radius: 6px;
font-family: inherit;
font-size: 14px;
outline: none;
}
#notebook-search-input:focus {
border-color: #339af0;
box-shadow: 0 0 0 2px rgba(51,154,240,0.16);
}
#notebook-search-results {
max-height: 58vh;
overflow-y: auto;
padding: 8px;
}
.search-empty {
padding: 24px 14px;
color: #868e96;
text-align: center;
font-size: 12px;
}
.search-result {
width: 100%;
display: block;
padding: 9px 10px;
margin: 0 0 4px;
border: 1px solid transparent;
border-radius: 6px;
background: transparent;
cursor: pointer;
text-align: left;
font-family: inherit;
}
.search-result:hover,
.search-result:focus {
background: #f8f9fa;
border-color: #dee2e6;
outline: none;
}
.search-result-meta {
display: flex;
align-items: center;
gap: 6px;
margin-bottom: 3px;
color: #1971c2;
font-size: 11px;
font-weight: 700;
}
.search-result-snippet {
color: #495057;
font-family: 'JetBrains Mono', monospace;
font-size: 11px;
white-space: nowrap;
overflow: hidden;
text-overflow: ellipsis;
}
.search-modal-foot {
display: flex;
justify-content: space-between;
align-items: center;
gap: 10px;
padding: 8px 14px;
border-top: 1px solid #e9ecef;
color: #adb5bd;
font-size: 10px;
background: #f8f9fa;
}

.backup-desc {
font-size: 12px;
line-height: 1.5;
Expand Down Expand Up @@ -967,6 +1120,7 @@
<div id="topbar">
<span id="app-logo">mathnote</span>
<div id="topbar-right">
<button id="search-btn" title="Search notebooks (Ctrl/Cmd+K)">Search</button>
<button id="info-btn" title="Information / Bilgi">Info</button>
<button id="examples-btn" title="Load examples">Examples</button>
<button id="backup-btn" title="Backup / Restore">Backup</button>
Expand Down Expand Up @@ -1012,6 +1166,32 @@
</div>
</div>


<div id="tab-context-menu" class="tab-context-menu" role="menu" aria-hidden="true">
<button type="button" data-action="rename" id="tab-menu-rename">Rename</button>
<button type="button" data-action="duplicate" id="tab-menu-duplicate">Duplicate</button>
</div>

<div id="undo-toast" class="undo-toast" role="status" aria-live="polite" aria-hidden="true">
<span id="undo-toast-text">Notebook closed.</span>
<button type="button" id="undo-close-btn">Undo</button>
</div>

<div id="search-modal" class="modal-overlay">
<div class="modal search-modal">
<div class="search-modal-head">
<div class="modal-title" id="search-modal-title">Search notebooks</div>
<input id="notebook-search-input" type="search" autocomplete="off" spellcheck="false"
placeholder="Search all notebooks...">
</div>
<div id="notebook-search-results"></div>
<div class="search-modal-foot">
<span id="search-result-count"></span>
<span>Esc</span>
</div>
</div>
</div>

<div id="new-file-modal" class="modal-overlay">
<div class="modal">
<div class="modal-title">Yeni Dosya Oluştur</div>
Expand Down
16 changes: 16 additions & 0 deletions scripts/verify-offline.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -60,6 +60,10 @@ if (!html.includes('rel="manifest" href="./manifest.webmanifest"')) {
if (!html.includes('id="examples-btn"')) {
violations.push('index.html: examples button missing');
}

for (const id of ['search-btn', 'search-modal', 'notebook-search-input', 'tab-context-menu', 'undo-toast', 'undo-close-btn']) {
if (!html.includes(`id="${id}"`)) violations.push(`index.html: ${id} missing`);
}
if (!html.includes("updateViaCache: 'none'")) {
violations.push('index.html: service worker bootstrap must bypass HTTP cache');
}
Expand Down Expand Up @@ -89,6 +93,18 @@ if (cssMatch) {
}

const sourceApp = await readFile(new URL('../src/app.js', import.meta.url), 'utf8');
for (const symbol of [
'renameNotebook',
'duplicateNotebook',
'reorderNotebooks',
'undoCloseNotebook',
'openNotebookSearch',
'renderNotebookSearchResults',
"event.key.toLowerCase() === 'k'"
]) {
if (!sourceApp.includes(symbol)) violations.push(`src/app.js: notebook management/search symbol missing: ${symbol}`);
}

if (sourceApp.includes("serviceWorker.register") || sourceApp.includes(".register('./sw.js'")) {
violations.push('src/app.js: service worker registration must stay independent from app boot');
}
Expand Down
Loading
Loading