169 lines
4.9 KiB
JavaScript
169 lines
4.9 KiB
JavaScript
|
|
/* ============================================================
|
|||
|
|
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();
|
|||
|
|
},
|
|||
|
|
});
|