Numex yayın: public/js/app-notes.js
This commit is contained in:
parent
48e0658663
commit
c8d0062503
168
public/js/app-notes.js
Normal file
168
public/js/app-notes.js
Normal file
|
|
@ -0,0 +1,168 @@
|
|||
/* ============================================================
|
||||
AURA OS — Uygulama A: Siber Not Defteri
|
||||
POST/GET /api/notes ile backend'e bağlanır
|
||||
============================================================ */
|
||||
|
||||
const NotesApp = {
|
||||
_textarea: null,
|
||||
_listEl: null,
|
||||
_msgEl: null,
|
||||
_saveBtn: null,
|
||||
};
|
||||
|
||||
/* API Yardımcıları */
|
||||
async function apiGetNotes() {
|
||||
const res = await fetch('/api/notes', { method: 'GET' });
|
||||
if (!res.ok) throw new Error('GET /api/notes -> ' + res.status);
|
||||
const data = await res.json();
|
||||
return data.notes || [];
|
||||
}
|
||||
|
||||
async function apiPostNote(text) {
|
||||
const res = await fetch('/api/notes', {
|
||||
method: 'POST',
|
||||
headers: { 'Content-Type': 'application/json' },
|
||||
body: JSON.stringify({ text }),
|
||||
});
|
||||
if (!res.ok) {
|
||||
const err = await res.json().catch(() => ({}));
|
||||
throw new Error((err && err.error) || 'POST /api/notes -> ' + res.status);
|
||||
}
|
||||
return await res.json();
|
||||
}
|
||||
|
||||
/* Not listesini render eder */
|
||||
function notesRenderList(notes) {
|
||||
const listEl = NotesApp._listEl;
|
||||
if (!listEl) return;
|
||||
|
||||
if (!notes || notes.length === 0) {
|
||||
listEl.innerHTML = '<div class="note-item"><div class="ni-empty">Henüz kayıtlı not yok.</div></div>';
|
||||
return;
|
||||
}
|
||||
|
||||
listEl.innerHTML = '';
|
||||
notes.forEach(n => {
|
||||
const time = n.createdAt ? new Date(n.createdAt) : null;
|
||||
let dateText = '';
|
||||
if (time) {
|
||||
const days = ['Pazar','Pazartesi','Salı','Çarşamba','Perşembe','Cuma','Cumartesi'];
|
||||
dateText =
|
||||
days[time.getDay()] + ' ' +
|
||||
String(time.getDate()).padStart(2,'0') + '.' +
|
||||
String(time.getMonth()+1).padStart(2,'0') + '.' +
|
||||
time.getFullYear() + ' ' +
|
||||
String(time.getHours()).padStart(2,'0') + ':' +
|
||||
String(time.getMinutes()).padStart(2,'0');
|
||||
}
|
||||
|
||||
const item = document.createElement('div');
|
||||
item.className = 'note-item';
|
||||
item.innerHTML =
|
||||
'<div class="ni-text"></div>' +
|
||||
(dateText ? '<div class="ni-date">▸ ' + dateText + '</div>' : '');
|
||||
item.querySelector('.ni-text').textContent = n.text;
|
||||
listEl.appendChild(item);
|
||||
});
|
||||
}
|
||||
|
||||
/* Notları yükle */
|
||||
async function refreshNotesList() {
|
||||
try {
|
||||
const notes = await apiGetNotes();
|
||||
notesRenderList(notes);
|
||||
return notes;
|
||||
} catch (err) {
|
||||
notesRenderList([]);
|
||||
return [];
|
||||
}
|
||||
}
|
||||
|
||||
/* Kaydet butonu */
|
||||
async function saveCurrentNote() {
|
||||
const textarea = NotesApp._textarea;
|
||||
const msgEl = NotesApp._msgEl;
|
||||
const btn = NotesApp._saveBtn;
|
||||
|
||||
const text = textarea ? textarea.value : '';
|
||||
if (!text.trim()) {
|
||||
flashMsg(msgEl, '⚠ Boş not kaydedilemez!', true);
|
||||
if (textarea) textarea.focus();
|
||||
return;
|
||||
}
|
||||
|
||||
if (btn) { btn.disabled = true; btn.textContent = '⏳ Kaydediliyor...'; }
|
||||
|
||||
try {
|
||||
const result = await apiPostNote(text);
|
||||
flashMsg(msgEl, '✓ Not kaydedildi! (' + result.notes.length + ' not)', false);
|
||||
if (textarea) textarea.value = '';
|
||||
notesRenderList(result.notes);
|
||||
} catch (err) {
|
||||
flashMsg(msgEl, '✗ Hata: ' + err.message, true);
|
||||
} finally {
|
||||
if (btn) { btn.disabled = false; btn.textContent = '💾 Kaydet'; }
|
||||
}
|
||||
}
|
||||
|
||||
function flashMsg(el, text, isErr) {
|
||||
if (!el) return;
|
||||
el.textContent = text;
|
||||
el.style.color = isErr ? '#ff6b6b' : '#39ff14';
|
||||
setTimeout(() => { if (el) el.textContent = ''; }, 4000);
|
||||
}
|
||||
|
||||
/* Uygulama başlat şablonu: DOM'daki <template> yapısını kullanır */
|
||||
function notesBuildContent() {
|
||||
const tpl = document.getElementById('tpl-note-editor');
|
||||
if (tpl && tpl.content) {
|
||||
return document.importNode(tpl.content, true).firstElementChild.innerHTML;
|
||||
}
|
||||
// Yedek HTML (template yoksa)
|
||||
return [
|
||||
'<div class="note-app">',
|
||||
' <textarea class="note-textarea" placeholder="Siber notunu yaz..."></textarea>',
|
||||
' <div class="note-toolbar"><button class="note-save-btn">💾 Kaydet</button></div>',
|
||||
' <div class="note-list"></div>',
|
||||
'</div>'
|
||||
].join('');
|
||||
}
|
||||
|
||||
/* registerApp kaydı — pencere içerik gövde şablonu + onLaunch hook */
|
||||
registerApp('notes', {
|
||||
name: 'Siber Not Defteri',
|
||||
icon: '📝',
|
||||
defaultWidth: 540,
|
||||
defaultHeight: 480,
|
||||
windowTitle: 'Siber Not Defteri — Aura OS',
|
||||
windowProps: { width: 540, height: 480 },
|
||||
|
||||
buildContent: notesBuildContent,
|
||||
|
||||
onLaunch(record, bodyEl) {
|
||||
// Body'ye template'i yerleştir
|
||||
const html = notesBuildContent();
|
||||
bodyEl.innerHTML = html;
|
||||
|
||||
NotesApp._textarea = bodyEl.querySelector('.note-textarea');
|
||||
NotesApp._listEl = bodyEl.querySelector('.note-list');
|
||||
NotesApp._saveBtn = bodyEl.querySelector('.note-save-btn');
|
||||
NotesApp._msgEl = bodyEl.querySelector('.note-saved-msg');
|
||||
|
||||
// Kaydet butonu olayı
|
||||
if (NotesApp._saveBtn) {
|
||||
NotesApp._saveBtn.addEventListener('click', saveCurrentNote);
|
||||
}
|
||||
|
||||
// Ctrl+S kısayolu
|
||||
bodyEl.addEventListener('keydown', (e) => {
|
||||
if ((e.ctrlKey || e.metaKey) && (e.key === 's' || e.key === 'S')) {
|
||||
e.preventDefault();
|
||||
saveCurrentNote();
|
||||
}
|
||||
});
|
||||
|
||||
// Mevcut notları listele
|
||||
refreshNotesList();
|
||||
},
|
||||
});
|
||||
Loading…
Reference in New Issue
Block a user