用trae自动生成的网页日记本小项目(AI编程确实强大)
·
用trae自动生成的网页日记本小项目
先看效果图



使用 localStorage 保存,关闭浏览器后数据不丢失;
存储键: my_diary_data
直接po代码
文件名是diary.html
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>我的日记</title>
<style>
* {
margin: 0;
padding: 0;
box-sizing: border-box;
}
body {
font-family: "Microsoft YaHei", "PingFang SC", sans-serif;
background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
min-height: 100vh;
padding: 30px 20px;
}
.container {
max-width: 1100px;
margin: 0 auto;
}
header {
text-align: center;
color: #fff;
margin-bottom: 30px;
}
header h1 {
font-size: 36px;
margin-bottom: 8px;
text-shadow: 0 2px 10px rgba(0,0,0,0.2);
}
header p {
font-size: 16px;
opacity: 0.9;
}
.stats {
display: flex;
justify-content: center;
gap: 30px;
margin-bottom: 30px;
}
.stat-card {
background: rgba(255,255,255,0.2);
backdrop-filter: blur(10px);
border: 1px solid rgba(255,255,255,0.3);
border-radius: 16px;
padding: 16px 28px;
color: #fff;
text-align: center;
}
.stat-card .number {
font-size: 32px;
font-weight: bold;
}
.stat-card .label {
font-size: 14px;
opacity: 0.9;
}
.calendar {
background: #fff;
border-radius: 20px;
box-shadow: 0 20px 60px rgba(0,0,0,0.2);
padding: 30px;
}
.calendar-header {
display: flex;
justify-content: space-between;
align-items: center;
margin-bottom: 25px;
padding-bottom: 15px;
border-bottom: 2px solid #f0f0f5;
}
.calendar-header h2 {
color: #333;
font-size: 24px;
}
.calendar-header .today {
background: linear-gradient(135deg, #667eea, #764ba2);
color: #fff;
padding: 8px 20px;
border-radius: 20px;
font-size: 14px;
cursor: pointer;
border: none;
transition: transform 0.2s;
}
.calendar-header .today:hover {
transform: scale(1.05);
}
.weekdays {
display: grid;
grid-template-columns: repeat(7, 1fr);
gap: 10px;
margin-bottom: 10px;
}
.weekdays div {
text-align: center;
font-weight: bold;
color: #888;
font-size: 14px;
padding: 10px 0;
}
.weekdays div.weekend {
color: #e74c3c;
}
.days {
display: grid;
grid-template-columns: repeat(7, 1fr);
gap: 10px;
}
.day {
aspect-ratio: 1;
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
background: #f8f9fc;
border-radius: 12px;
cursor: pointer;
transition: all 0.25s ease;
position: relative;
border: 2px solid transparent;
min-height: 70px;
}
.day:hover {
background: linear-gradient(135deg, #667eea, #764ba2);
color: #fff;
transform: translateY(-3px);
box-shadow: 0 8px 20px rgba(102, 126, 234, 0.3);
}
.day .date {
font-size: 20px;
font-weight: 600;
}
.day .month {
font-size: 11px;
opacity: 0.7;
margin-top: 2px;
}
.day.today {
background: linear-gradient(135deg, #667eea, #764ba2);
color: #fff;
border-color: #fff;
box-shadow: 0 4px 15px rgba(102, 126, 234, 0.4);
}
.day.has-content::after {
content: '';
position: absolute;
top: 8px;
right: 8px;
width: 8px;
height: 8px;
background: #ff6b6b;
border-radius: 50%;
}
.day.other-month {
opacity: 0.4;
}
.day.weekend .date {
color: #e74c3c;
}
.day:hover.weekend .date {
color: #fff;
}
.day.today.weekend .date {
color: #fff;
}
.modal {
display: none;
position: fixed;
top: 0;
left: 0;
width: 100%;
height: 100%;
background: rgba(0,0,0,0.5);
backdrop-filter: blur(5px);
z-index: 1000;
justify-content: center;
align-items: center;
padding: 20px;
}
.modal.show {
display: flex;
animation: fadeIn 0.3s ease;
}
@keyframes fadeIn {
from { opacity: 0; }
to { opacity: 1; }
}
.modal-content {
background: #fff;
border-radius: 20px;
width: 100%;
max-width: 500px;
box-shadow: 0 30px 80px rgba(0,0,0,0.3);
overflow: hidden;
animation: slideUp 0.3s ease;
}
@keyframes slideUp {
from { transform: translateY(30px); opacity: 0; }
to { transform: translateY(0); opacity: 1; }
}
.modal-header {
background: linear-gradient(135deg, #667eea, #764ba2);
color: #fff;
padding: 20px 25px;
display: flex;
justify-content: space-between;
align-items: center;
}
.modal-header h3 {
font-size: 18px;
}
.modal-close {
background: none;
border: none;
color: #fff;
font-size: 24px;
cursor: pointer;
opacity: 0.8;
transition: opacity 0.2s;
line-height: 1;
}
.modal-close:hover {
opacity: 1;
}
.modal-body {
padding: 25px;
}
.modal-body textarea {
width: 100%;
height: 200px;
border: 2px solid #e0e0e8;
border-radius: 12px;
padding: 15px;
font-size: 15px;
font-family: inherit;
resize: vertical;
transition: border-color 0.2s;
outline: none;
}
.modal-body textarea:focus {
border-color: #667eea;
}
.modal-body textarea::placeholder {
color: #bbb;
}
.modal-footer {
padding: 0 25px 25px;
display: flex;
gap: 12px;
justify-content: flex-end;
}
.btn {
padding: 10px 24px;
border: none;
border-radius: 10px;
font-size: 15px;
cursor: pointer;
transition: all 0.2s;
font-weight: 600;
}
.btn-save {
background: linear-gradient(135deg, #667eea, #764ba2);
color: #fff;
}
.btn-save:hover {
transform: translateY(-2px);
box-shadow: 0 6px 18px rgba(102, 126, 234, 0.4);
}
.btn-delete {
background: #ffecec;
color: #e74c3c;
}
.btn-delete:hover {
background: #ffd9d9;
}
.empty-hint {
text-align: center;
color: #bbb;
font-size: 14px;
margin-top: 15px;
}
@media (max-width: 600px) {
header h1 {
font-size: 26px;
}
.calendar {
padding: 20px 15px;
}
.day {
min-height: 50px;
padding: 5px;
}
.day .date {
font-size: 16px;
}
.day .month {
font-size: 10px;
}
.stats {
flex-wrap: wrap;
gap: 15px;
}
.stat-card {
padding: 12px 20px;
}
.stat-card .number {
font-size: 24px;
}
}
</style>
</head>
<body>
<div class="container">
<header>
<h1>📖 我的日记</h1>
<p>记录每一天的美好与成长</p>
</header>
<div class="stats">
<div class="stat-card">
<div class="number" id="totalDays">0</div>
<div class="label">记录天数</div>
</div>
<div class="stat-card">
<div class="number" id="totalWords">0</div>
<div class="label">累计字数</div>
</div>
<div class="stat-card">
<div class="number" id="streakDays">0</div>
<div class="label">连续记录</div>
</div>
</div>
<div class="calendar">
<div class="calendar-header">
<h2 id="monthTitle"></h2>
<button class="today" onclick="goToday()">回到今天</button>
</div>
<div class="weekdays">
<div class="weekend">日</div>
<div>一</div>
<div>二</div>
<div>三</div>
<div>四</div>
<div>五</div>
<div class="weekend">六</div>
</div>
<div class="days" id="daysContainer"></div>
</div>
</div>
<div class="modal" id="modal">
<div class="modal-content">
<div class="modal-header">
<h3 id="modalTitle">编辑日记</h3>
<button class="modal-close" onclick="closeModal()">×</button>
</div>
<div class="modal-body">
<textarea id="diaryContent" placeholder="写下这一天的工作内容、心情、感悟..."></textarea>
<div class="empty-hint" id="emptyHint">还没有记录,开始写下你的故事吧 ✨</div>
</div>
<div class="modal-footer">
<button class="btn btn-delete" id="deleteBtn" onclick="deleteDiary()" style="display:none;">删除</button>
<button class="btn btn-save" onclick="saveDiary()">保存</button>
</div>
</div>
</div>
<script>
const STORAGE_KEY = 'my_diary_data';
let diaryData = JSON.parse(localStorage.getItem(STORAGE_KEY) || '{}');
let currentDate = new Date();
let editingDateKey = null;
function formatDateKey(date) {
const y = date.getFullYear();
const m = String(date.getMonth() + 1).padStart(2, '0');
const d = String(date.getDate()).padStart(2, '0');
return `${y}-${m}-${d}`;
}
function isSameDay(d1, d2) {
return d1.getFullYear() === d2.getFullYear() &&
d1.getMonth() === d2.getMonth() &&
d1.getDate() === d2.getDate();
}
function renderCalendar() {
const year = currentDate.getFullYear();
const month = currentDate.getMonth();
const monthNames = ['一月', '二月', '三月', '四月', '五月', '六月',
'七月', '八月', '九月', '十月', '十一月', '十二月'];
document.getElementById('monthTitle').textContent = `${year}年 ${monthNames[month]}`;
const firstDay = new Date(year, month, 1);
const lastDay = new Date(year, month + 1, 0);
const startWeekday = firstDay.getDay();
const daysInMonth = lastDay.getDate();
const prevMonthDays = new Date(year, month, 0).getDate();
const container = document.getElementById('daysContainer');
container.innerHTML = '';
const today = new Date();
for (let i = 0; i < startWeekday; i++) {
const dayEl = document.createElement('div');
dayEl.className = 'day other-month';
const prevDay = prevMonthDays - startWeekday + i + 1;
const prevDate = new Date(year, month - 1, prevDay);
dayEl.innerHTML = `
<span class="date">${prevDay}</span>
<span class="month">${prevDate.getMonth() + 1}月</span>
`;
if (prevDate.getDay() === 0 || prevDate.getDay() === 6) {
dayEl.classList.add('weekend');
}
dayEl.onclick = () => openModal(prevDate);
container.appendChild(dayEl);
}
for (let d = 1; d <= daysInMonth; d++) {
const dayEl = document.createElement('div');
const dateObj = new Date(year, month, d);
const dateKey = formatDateKey(dateObj);
dayEl.className = 'day';
if (isSameDay(dateObj, today)) dayEl.classList.add('today');
if (dateObj.getDay() === 0 || dateObj.getDay() === 6) dayEl.classList.add('weekend');
if (diaryData[dateKey]) dayEl.classList.add('has-content');
dayEl.innerHTML = `<span class="date">${d}</span>`;
dayEl.onclick = () => openModal(dateObj);
container.appendChild(dayEl);
}
const totalCells = startWeekday + daysInMonth;
const remaining = (7 - (totalCells % 7)) % 7;
for (let i = 1; i <= remaining; i++) {
const dayEl = document.createElement('div');
dayEl.className = 'day other-month';
const nextDate = new Date(year, month + 1, i);
dayEl.innerHTML = `
<span class="date">${i}</span>
<span class="month">${nextDate.getMonth() + 1}月</span>
`;
if (nextDate.getDay() === 0 || nextDate.getDay() === 6) {
dayEl.classList.add('weekend');
}
dayEl.onclick = () => openModal(nextDate);
container.appendChild(dayEl);
}
updateStats();
}
function openModal(date) {
editingDateKey = formatDateKey(date);
const weekdayNames = ['星期日', '星期一', '星期二', '星期三', '星期四', '星期五', '星期六'];
const title = `${date.getFullYear()}年${date.getMonth() + 1}月${date.getDate()}日 ${weekdayNames[date.getDay()]}`;
document.getElementById('modalTitle').textContent = title;
const content = diaryData[editingDateKey] || '';
document.getElementById('diaryContent').value = content;
const deleteBtn = document.getElementById('deleteBtn');
const emptyHint = document.getElementById('emptyHint');
if (content) {
deleteBtn.style.display = 'block';
emptyHint.style.display = 'none';
} else {
deleteBtn.style.display = 'none';
emptyHint.style.display = 'block';
}
document.getElementById('modal').classList.add('show');
setTimeout(() => document.getElementById('diaryContent').focus(), 100);
}
function closeModal() {
document.getElementById('modal').classList.remove('show');
editingDateKey = null;
}
function saveDiary() {
const content = document.getElementById('diaryContent').value.trim();
if (!editingDateKey) return;
if (content) {
diaryData[editingDateKey] = content;
} else {
delete diaryData[editingDateKey];
}
localStorage.setItem(STORAGE_KEY, JSON.stringify(diaryData));
renderCalendar();
closeModal();
}
function deleteDiary() {
if (!editingDateKey) return;
if (confirm('确定要删除这一天的日记吗?')) {
delete diaryData[editingDateKey];
localStorage.setItem(STORAGE_KEY, JSON.stringify(diaryData));
renderCalendar();
closeModal();
}
}
function updateStats() {
const entries = Object.entries(diaryData).filter(([_, v]) => v.trim());
document.getElementById('totalDays').textContent = entries.length;
const totalWords = entries.reduce((sum, [_, v]) => sum + v.length, 0);
document.getElementById('totalWords').textContent = totalWords;
let streak = 0;
const today = new Date();
for (let i = 0; i < 365; i++) {
const d = new Date(today);
d.setDate(d.getDate() - i);
if (diaryData[formatDateKey(d)] && diaryData[formatDateKey(d)].trim()) {
streak++;
} else {
break;
}
}
document.getElementById('streakDays').textContent = streak;
}
function goToday() {
currentDate = new Date();
renderCalendar();
}
document.getElementById('modal').addEventListener('click', function(e) {
if (e.target === this) closeModal();
});
document.addEventListener('keydown', function(e) {
if (e.key === 'Escape') closeModal();
if (e.key === 'Enter' && (e.ctrlKey || e.metaKey)) saveDiary();
});
renderCalendar();
</script>
</body>
</html>
更多推荐



所有评论(0)