HTML5 Not Defteri yapalım.
Cepten Notlar - Mobil Not Defteri
📭
Henüz not bulunmuyor.
Sağ üstteki "+" butonuna basarak ilk notunuzu ekleyin!
Tema Seçin
İşlem başarılı
<!DOCTYPE html><html lang="tr" class="h-full">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Cepten Notlar - Mobil Not Defteri</title>
<!-- Tailwind CSS CDN -->
<script src="https://cdn.tailwindcss.com"></script>
<script>
tailwind.config = {
darkMode: 'class',
theme: {
extend: {
colors: {
themeDark: { bg: '#0f172a', card: '#1e293b', text: '#f8fafc', primary: '#3b82f6', border: '#334155' },
themeLight: { bg: '#f1f5f9', card: '#ffffff', text: '#0f172a', primary: '#2563eb', border: '#e2e8f0' },
themeCyber: { bg: '#05050a', card: '#121124', text: '#00ffcc', primary: '#ff007f', border: '#2a265f' },
themePastel: { bg: '#fdf4f5', card: '#ffffff', text: '#4a4046', primary: '#d97706', border: '#f5d0d6' }
}
}
}
}
</script>
<style>
/* 9:16 Responsive Container Constraints for desktop, full screen on mobile */
@media (min-width: 640px) {
.phone-frame {
width: 100%;
max-width: 420px;
height: 85vh;
max-height: 840px;
box-shadow: 0 25px 50px -12px rgba(0, 0, 0, 0.4);
border-radius: 2.5rem;
border: 8px solid #1e293b;
overflow: hidden;
}
}
@media (max-width: 639px) {
.phone-frame {
width: 100vw;
height: 100vh;
border-radius: 0;
}
}
/* Custom Scrollbar */
::-webkit-scrollbar { width: 5px; height: 5px; }
::-webkit-scrollbar-track { background: transparent; }
::-webkit-scrollbar-thumb { background: rgba(150,150,150,0.3); border-radius: 10px; }
</style>
</head>
<body class="h-full flex items-center justify-center transition-colors duration-300" id="bodyTag">
<!-- Ana Çerçeve (9:16 Oranı / Mobil Görünüm) -->
<div id="appContainer" class="phone-frame flex flex-col relative transition-colors duration-300 shadow-2xl">
<!-- Üst Bilgi Çubuğu (Header) -->
<header class="px-5 py-4 flex items-center justify-between border-b transition-colors duration-300 z-10" id="headerEl">
<div class="flex items-center space-x-2">
<div class="w-8 h-8 rounded-xl flex items-center justify-center font-bold text-lg shadow-md" id="appLogo">📝</div>
<div>
<h1 class="font-bold text-base leading-tight tracking-tight" id="appTitle">Cepten Notlar</h1>
<span class="text-xs opacity-75" id="noteCountBadge">0 Not</span>
</div>
</div>
<div class="flex items-center space-x-2">
<!-- Tema Değiştirme Butonu -->
<button onclick="toggleThemeModal()" class="p-2 rounded-xl transition hover:scale-105 active:scale-95 shadow-sm" id="themeBtn" title="Tema Değiştir">
<svg class="w-5 h-5" fill="none" stroke="currentColor" viewBox="0 0 24 24"><path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M12 3v1m0 16v1m9-9h-1M4 12H3m15.364 6.364l-.707-.707M6.343 6.343l-.707-.707m12.728 0l-.707.707M6.343 17.657l-.707.707M16 12a4 4 0 11-8 0 4 4 0 018 0z"></path></svg>
</button>
<!-- Yeni Not Ekleme Butonu -->
<button onclick="openEditor()" class="p-2 rounded-xl text-white transition hover:scale-105 active:scale-95 shadow-md flex items-center justify-center" id="addBtn" title="Yeni Not">
<svg class="w-5 h-5" fill="none" stroke="currentColor" viewBox="0 0 24 24"><path stroke-linecap="round" stroke-linejoin="round" stroke-width="2.5" d="M12 4v16m8-8H4"></path></svg>
</button>
</div>
</header>
<!-- Arama ve Filtreleme Alanı -->
<div class="px-4 py-3 border-b transition-colors duration-300" id="searchBarEl">
<div class="relative">
<span class="absolute inset-y-0 left-0 pl-3 flex items-center pointer-events-none opacity-50">
<svg class="w-4 h-4" fill="none" stroke="currentColor" viewBox="0 0 24 24"><path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M21 21l-6-6m2-5a7 7 0 11-14 0 7 7 0 0114 0z"></path></svg>
</span>
<input type="text" id="searchInput" oninput="filterNotes()" placeholder="Notlarda ara (başlık, içerik, etiket)..."
class="w-full pl-9 pr-4 py-2 rounded-xl text-sm border outline-none transition duration-200 bg-opacity-50">
</div>
</div>
<!-- Not Listesi Ekranı -->
<div class="flex-1 overflow-y-auto p-4 space-y-3" id="notesListContainer">
<!-- Dinamik Notlar Buraya Gelecek -->
</div>
<!-- Boş Durum Görseli -->
<div id="emptyState" class="hidden flex-1 flex flex-col items-center justify-center p-8 text-center opacity-60">
<div class="text-5xl mb-3">📭</div>
<p class="text-sm font-medium">Henüz not bulunmuyor.</p>
<p class="text-xs mt-1">Sağ üstteki "+" butonuna basarak ilk notunuzu ekleyin!</p>
</div>
<!-- Not Düzenleme / Ekleme Modal / Ekranı -->
<div id="editorScreen" class="absolute inset-0 z-20 flex flex-col transform translate-y-full transition-transform duration-300 ease-in-out shadow-2xl" style="background: inherit;">
<div class="px-5 py-4 flex items-center justify-between border-b" id="editorHeader">
<button onclick="closeEditor()" class="px-3 py-1.5 rounded-xl text-sm font-medium transition hover:opacity-75 flex items-center space-x-1">
<span>← Geri</span>
</button>
<h2 class="font-bold text-sm" id="editorTitleText">Not Düzenle</h2>
<button onclick="saveNote()" class="px-4 py-1.5 rounded-xl text-sm font-semibold text-white transition shadow-sm" id="saveNoteBtn">Kaydet</button>
</div>
<div class="flex-1 overflow-y-auto p-5 space-y-4">
<!-- Başlık -->
<div>
<label class="block text-xs font-semibold mb-1 opacity-80 uppercase tracking-wider">Başlık</label>
<input type="text" id="noteTitleInput" placeholder="Not başlığı girin..." class="w-full px-3 py-2.5 rounded-xl text-sm border outline-none bg-opacity-30">
</div>
<!-- Kategori / Etiket -->
<div>
<label class="block text-xs font-semibold mb-1 opacity-80 uppercase tracking-wider">Etiket / Kategori</label>
<input type="text" id="noteCategoryInput" placeholder="Örn: İş, Kişisel, Alışveriş..." class="w-full px-3 py-2.5 rounded-xl text-sm border outline-none bg-opacity-30">
</div>
<!-- Hızlı Sembol & Emoji Çubuğu -->
<div>
<label class="block text-xs font-semibold mb-1 opacity-80 uppercase tracking-wider">Hızlı Sembol & Emoji Ekle</label>
<div class="flex flex-wrap gap-1.5 p-2 rounded-xl border bg-black bg-opacity-5">
<button type="button" onclick="insertSymbol('⭐')" class="p-1.5 rounded hover:bg-black hover:bg-opacity-10 text-sm">⭐</button>
<button type="button" onclick="insertSymbol('🔥')" class="p-1.5 rounded hover:bg-black hover:bg-opacity-10 text-sm">🔥</button>
<button type="button" onclick="insertSymbol('💡')" class="p-1.5 rounded hover:bg-black hover:bg-opacity-10 text-sm">💡</button>
<button type="button" onclick="insertSymbol('✅')" class="p-1.5 rounded hover:bg-black hover:bg-opacity-10 text-sm">✅</button>
<button type="button" onclick="insertSymbol('📌')" class="p-1.5 rounded hover:bg-black hover:bg-opacity-10 text-sm">📌</button>
<button type="button" onclick="insertSymbol('❤️')" class="p-1.5 rounded hover:bg-black hover:bg-opacity-10 text-sm">❤️</button>
<button type="button" onclick="insertSymbol('🎯')" class="p-1.5 rounded hover:bg-black hover:bg-opacity-10 text-sm">🎯</button>
<button type="button" onclick="insertSymbol('📅')" class="p-1.5 rounded hover:bg-black hover:bg-opacity-10 text-sm">📅</button>
<button type="button" onclick="insertSymbol('💰')" class="p-1.5 rounded hover:bg-black hover:bg-opacity-10 text-sm">💰</button>
<button type="button" onclick="insertSymbol('⚡')" class="p-1.5 rounded hover:bg-black hover:bg-opacity-10 text-sm">⚡</button>
<button type="button" onclick="insertSymbol('✓')" class="p-1.5 rounded hover:bg-black hover:bg-opacity-10 text-sm">✓</button>
<button type="button" onclick="insertSymbol('✗')" class="p-1.5 rounded hover:bg-black hover:bg-opacity-10 text-sm">✗</button>
</div>
</div>
<!-- İçerik Alanı -->
<div class="flex-1 flex flex-col">
<label class="block text-xs font-semibold mb-1 opacity-80 uppercase tracking-wider">Not İçeriği</label>
<textarea id="noteContentInput" rows="6" placeholder="Notunuzu buraya yazın..." class="w-full flex-1 px-3 py-2.5 rounded-xl text-sm border outline-none bg-opacity-30 resize-none"></textarea>
</div>
<!-- Resim Yükleme Alanı -->
<div>
<label class="block text-xs font-semibold mb-1 opacity-80 uppercase tracking-wider">Görsel Ekle</label>
<input type="file" id="imageUploadInput" accept="image/*" onchange="handleImageUpload(event)" class="block w-full text-xs file:mr-4 file:py-2 file:px-4 file:rounded-xl file:border-0 file:text-xs file:font-semibold file:bg-blue-50 file:text-blue-700 hover:file:bg-blue-100 cursor-pointer">
<!-- Yüklenen Resim Önizleme -->
<div id="imagePreviewContainer" class="mt-2 relative hidden">
<img id="noteImagePreview" src="" alt="Önizleme" class="w-full h-32 object-cover rounded-xl border">
<button type="button" onclick="removeImage()" class="absolute top-2 right-2 bg-red-600 text-white rounded-full p-1 text-xs shadow hover:bg-red-700">❌</button>
</div>
</div>
</div>
</div>
<!-- Tema Seçim Paneli / Modal -->
<div id="themeModal" class="absolute inset-0 z-30 bg-black bg-opacity-60 backdrop-blur-sm hidden flex items-center justify-center p-4">
<div class="w-full max-w-xs rounded-2xl p-5 shadow-2xl border transition-all" id="themeModalContent">
<div class="flex justify-between items-center mb-4">
<h3 class="font-bold text-sm">Tema Seçin</h3>
<button onclick="toggleThemeModal()" class="text-xs opacity-70 hover:opacity-100 font-bold px-2 py-1">✕ Kapat</button>
</div>
<div class="space-y-2">
<button onclick="setTheme('dark')" class="w-full flex items-center justify-between p-3 rounded-xl border text-sm font-medium transition hover:scale-[1.02]">
<span class="flex items-center space-x-2"><span>🌙</span><span>Modern Karanlık</span></span>
<span class="w-4 h-4 rounded-full bg-slate-900 border border-slate-700"></span>
</button>
<button onclick="setTheme('light')" class="w-full flex items-center justify-between p-3 rounded-xl border text-sm font-medium transition hover:scale-[1.02]">
<span class="flex items-center space-x-2"><span>☀️</span><span>Pastel Aydınlık</span></span>
<span class="w-4 h-4 rounded-full bg-white border border-slate-300"></span>
</button>
<button onclick="setTheme('cyber')" class="w-full flex items-center justify-between p-3 rounded-xl border text-sm font-medium transition hover:scale-[1.02]">
<span class="flex items-center space-x-2"><span>⚡</span><span>Cyberpunk Neon</span></span>
<span class="w-4 h-4 rounded-full bg-[#05050a] border border-[#ff007f]"></span>
</button>
<button onclick="setTheme('pastel')" class="w-full flex items-center justify-between p-3 rounded-xl border text-sm font-medium transition hover:scale-[1.02]">
<span class="flex items-center space-x-2"><span>🌸</span><span>Pastel Pembe</span></span>
<span class="w-4 h-4 rounded-full bg-[#fdf4f5] border border-[#d97706]"></span>
</button>
</div>
</div>
</div>
<!-- Bildirim / Mesaj Kutusu -->
<div id="toast" class="absolute bottom-5 left-1/2 transform -translate-x-1/2 px-4 py-2 rounded-xl text-xs font-semibold shadow-lg transition-all duration-300 opacity-0 pointer-events-none z-40 bg-black text-white">
İşlem başarılı
</div>
</div>
<!-- JavaScript Uygulama Mantığı -->
<script>
// Uygulama Durumu (State)
let notes = JSON.parse(localStorage.getItem('cepten_notes') || '[]');
let currentTheme = localStorage.getItem('cepten_theme') || 'dark';
let editingNoteId = null;
let currentImageBase64 = '';
// Sayfa Yüklendiğinde Çalışacaklar
window.onload = function() {
setTheme(currentTheme);
renderNotes();
};
// Tema Yönetimi
function setTheme(themeName) {
currentTheme = themeName;
localStorage.setItem('cepten_theme', themeName);
const body = document.getElementById('bodyTag');
const container = document.getElementById('appContainer');
const header = document.getElementById('headerEl');
const searchBar = document.getElementById('searchBarEl');
const searchInput = document.getElementById('searchInput');
const editorScreen = document.getElementById('editorScreen');
const editorHeader = document.getElementById('editorHeader');
const noteTitleInput = document.getElementById('noteTitleInput');
const noteCategoryInput = document.getElementById('noteCategoryInput');
const noteContentInput = document.getElementById('noteContentInput');
const themeModalContent = document.getElementById('themeModalContent');
const addBtn = document.getElementById('addBtn');
const saveNoteBtn = document.getElementById('saveNoteBtn');
// Sınıfları Temizle
container.className = "phone-frame flex flex-col relative transition-colors duration-300 shadow-2xl";
let themeConfig = {};
if (themeName === 'dark') {
themeConfig = { bg: '#0f172a', card: '#1e293b', text: '#f8fafc', primary: '#3b82f6', border: '#334155', inputBg: '#0f172a' };
} else if (themeName === 'light') {
themeConfig = { bg: '#e2e8f0', card: '#f8fafc', text: '#0f172a', primary: '#2563eb', border: '#cbd5e1', inputBg: '#ffffff' };
} else if (themeName === 'cyber') {
themeConfig = { bg: '#05050a', card: '#121124', text: '#00ffcc', primary: '#ff007f', border: '#2a265f', inputBg: '#05050a' };
} else if (themeName === 'pastel') {
themeConfig = { bg: '#fce7f0', card: '#ffffff', text: '#4a4046', primary: '#d97706', border: '#f5d0d6', inputBg: '#fff5f7' };
}
container.style.backgroundColor = themeConfig.bg;
container.style.color = themeConfig.text;
editorScreen.style.backgroundColor = themeConfig.bg;
editorScreen.style.color = themeConfig.text;
header.style.borderColor = themeConfig.border;
searchBar.style.borderColor = themeConfig.border;
editorHeader.style.borderColor = themeConfig.border;
themeModalContent.style.backgroundColor = themeConfig.card;
themeModalContent.style.borderColor = themeConfig.border;
searchInput.style.backgroundColor = themeConfig.inputBg;
searchInput.style.borderColor = themeConfig.border;
searchInput.style.color = themeConfig.text;
noteTitleInput.style.backgroundColor = themeConfig.inputBg;
noteTitleInput.style.borderColor = themeConfig.border;
noteTitleInput.style.color = themeConfig.text;
noteCategoryInput.style.backgroundColor = themeConfig.inputBg;
noteCategoryInput.style.borderColor = themeConfig.border;
noteCategoryInput.style.color = themeConfig.text;
noteContentInput.style.backgroundColor = themeConfig.inputBg;
noteContentInput.style.borderColor = themeConfig.border;
noteContentInput.style.color = themeConfig.text;
addBtn.style.backgroundColor = themeConfig.primary;
saveNoteBtn.style.backgroundColor = themeConfig.primary;
document.getElementById('themeModal').classList.add('hidden');
renderNotes();
}
function toggleThemeModal() {
const modal = document.getElementById('themeModal');
modal.classList.toggle('hidden');
}
// Not Listeleme & Filtreleme
function renderNotes(filterText = '') {
const container = document.getElementById('notesListContainer');
const emptyState = document.getElementById('emptyState');
const countBadge = document.getElementById('noteCountBadge');
container.innerHTML = '';
const filtered = notes.filter(n => {
const text = filterText.toLowerCase();
return n.title.toLowerCase().includes(text) ||
n.content.toLowerCase().includes(text) ||
(n.category && n.category.toLowerCase().includes(text));
});
countBadge.innerText = `${notes.length} Not`;
if (filtered.length === 0) {
emptyState.classList.remove('hidden');
return;
} else {
emptyState.classList.add('hidden');
}
// Kart stilleri temaya göre ayarlanır
let cardBg = '#1e293b', cardBorder = '#334155', badgeBg = '#334155';
if (currentTheme === 'light') { cardBg = '#ffffff'; cardBorder = '#e2e8f0'; badgeBg = '#e2e8f0'; }
else if (currentTheme === 'cyber') { cardBg = '#121124'; cardBorder = '#2a265f'; badgeBg = '#2a265f'; }
else if (currentTheme === 'pastel') { cardBg = '#ffffff'; cardBorder = '#f5d0d6'; badgeBg = '#fae1e6'; }
filtered.sort((a, b) => b.date - a.date).forEach(note => {
const dateStr = new Date(note.date).toLocaleDateString('tr-TR', { day: 'numeric', month: 'short', hour: '2-digit', minute: '2-digit' });
const card = document.createElement('div');
card.className = "p-4 rounded-2xl border transition-all duration-200 hover:scale-[1.01] shadow-sm flex flex-col space-y-2 relative group";
card.style.backgroundColor = cardBg;
card.style.borderColor = cardBorder;
let imageHtml = '';
if (note.image) {
imageHtml = `<div class="mt-2"><img src="${note.image}" class="w-full h-28 object-cover rounded-xl border opacity-90" alt="Not Görseli"></div>`;
}
card.innerHTML = `
<div class="flex items-start justify-between">
<h3 class="font-bold text-sm line-clamp-1 pr-6">${escapeHtml(note.title || 'Başlıksız Not')}</h3>
<div class="absolute top-3 right-3 flex items-center space-x-1 opacity-80 group-hover:opacity-100">
<button onclick="editNote('${note.id}')" class="p-1 rounded hover:bg-black hover:bg-opacity-10 text-xs" title="Düzenle">✏️</button>
<button onclick="deleteNote('${note.id}')" class="p-1 rounded hover:bg-black hover:bg-opacity-10 text-xs" title="Sil">🗑️</button>
</div>
</div>
${note.category ? `<span class="self-start px-2 py-0.5 rounded-md text-[10px] font-semibold uppercase tracking-wider" style="background-color: ${badgeBg}; opacity: 0.9;">${escapeHtml(note.category)}</span>` : ''}
<p class="text-xs opacity-80 line-clamp-2 whitespace-pre-wrap">${escapeHtml(note.content)}</p>
${imageHtml}
<div class="flex justify-between items-center pt-1 text-[10px] opacity-60">
<span>${dateStr}</span>
</div>
`;
container.appendChild(card);
});
}
function filterNotes() {
const query = document.getElementById('searchInput').value;
renderNotes(query);
}
// CRUD İşlemleri
function openEditor(noteId = null) {
editingNoteId = noteId;
currentImageBase64 = '';
document.getElementById('imagePreviewContainer').classList.add('hidden');
document.getElementById('imageUploadInput').value = '';
const titleInput = document.getElementById('noteTitleInput');
const categoryInput = document.getElementById('noteCategoryInput');
const contentInput = document.getElementById('noteContentInput');
const editorTitleText = document.getElementById('editorTitleText');
if (noteId) {
const note = notes.find(n => n.id === noteId);
if (note) {
titleInput.value = note.title;
categoryInput.value = note.category || '';
contentInput.value = note.content;
if (note.image) {
currentImageBase64 = note.image;
document.getElementById('noteImagePreview').src = note.image;
document.getElementById('imagePreviewContainer').classList.remove('hidden');
}
editorTitleText.innerText = 'Notu Düzenle';
}
} else {
titleInput.value = '';
categoryInput.value = '';
contentInput.value = '';
editorTitleText.innerText = 'Yeni Not Ekle';
}
document.getElementById('editorScreen').style.transform = 'translateY(0)';
}
function closeEditor() {
document.getElementById('editorScreen').style.transform = 'translateY(100%)';
editingNoteId = null;
}
function saveNote() {
const title = document.getElementById('noteTitleInput').value.trim();
const category = document.getElementById('noteCategoryInput').value.trim();
const content = document.getElementById('noteContentInput').value.trim();
if (!title && !content) {
showToast('Lütfen en az başlık veya içerik girin!');
return;
}
if (editingNoteId) {
const index = notes.findIndex(n => n.id === editingNoteId);
if (index !== -1) {
notes[index].title = title;
notes[index].category = category;
notes[index].content = content;
notes[index].image = currentImageBase64;
notes[index].date = Date.now();
}
showToast('Not güncellendi!');
} else {
const newNote = {
id: '_' + Math.random().toString(36).substr(2, 9),
title: title,
category: category,
content: content,
image: currentImageBase64,
date: Date.now()
};
notes.push(newNote);
showToast('Not eklendi!');
}
localStorage.setItem('cepten_notes', JSON.stringify(notes));
closeEditor();
renderNotes();
}
function editNote(id) {
openEditor(id);
}
function deleteNote(id) {
if (confirm('Bu notu silmek istediğinize emin misiniz?')) {
notes = notes.filter(n => n.id !== id);
localStorage.setItem('cepten_notes', JSON.stringify(notes));
renderNotes();
showToast('Not silindi.');
}
}
// Resim Yükleme (Base64)
function handleImageUpload(event) {
const file = event.target.files[0];
if (!file) return;
const reader = new FileReader();
reader.onload = function(e) {
currentImageBase64 = e.target.result;
document.getElementById('noteImagePreview').src = currentImageBase64;
document.getElementById('imagePreviewContainer').classList.remove('hidden');
};
reader.readAsDataURL(file);
}
function removeImage() {
currentImageBase64 = '';
document.getElementById('imageUploadInput').value = '';
document.getElementById('imagePreviewContainer').classList.add('hidden');
}
// Sembol / Emoji Ekleme
function insertSymbol(symbol) {
const textarea = document.getElementById('noteContentInput');
const start = textarea.selectionStart;
const end = textarea.selectionEnd;
const text = textarea.value;
textarea.value = text.substring(0, start) + symbol + text.substring(end);
textarea.selectionStart = textarea.selectionEnd = start + symbol.length;
textarea.focus();
}
// Bildirim Kutusu (Toast)
function showToast(message) {
const toast = document.getElementById('toast');
toast.innerText = message;
toast.classList.remove('opacity-0');
toast.classList.add('opacity-100');
setTimeout(() => {
toast.classList.remove('opacity-100');
toast.classList.add('opacity-0');
}, 2000);
}
// Güvenlik / XSS Engelleyici
function escapeHtml(str) {
return str.replace(/&/g, "&").replace(/</g, "<").replace(/>/g, ">").replace(/"/g, """).replace(/'/g, "'");
}
</script>
</body>
</html>
Hiç yorum yok:
Yorum Gönder