🎁 买Hostinger主机,免费获得此源码 | zuofuye8.cn

习惯打卡追踪器

小习惯,大改变。每天进步一点点。

🎯
聚焦每日行动
不追求完美,只追求持续
📊
数据本地存储
你的隐私,你做主
🔥
记录连续打卡
用坚持点燃内心的火焰
🧘
安静模式
减少干扰,专注当下
数据仅保存在你的浏览器中
📋 我的习惯
今天
?
快捷键
打卡/取消空格
前一天
后一天
回到今天T
安静模式Q
0
习惯总数
0
今日完成
0
最长连续
0%
完成率
📌 今日习惯

适合哪些人用?

👥 想养成运动、阅读、早起等好习惯的人群

核心功能亮点

为什么选择自建而不用现成App?

📊 Keep/打卡APP:需注册,数据在别人服务器;自建打卡追踪器:数据完全私密,界面清爽,可定制习惯分类

常见问题

❓ 21天真的能养成习惯吗?
研究表明养成习惯平均需要66天,但21天是建立初始习惯回路的关键期,坚持21天后会明显降低坚持难度。
❓ 同时追踪多少个习惯合适?
建议同时追踪不超过3个习惯,专注度越高,养成成功率越高。
❓ 打卡中断了怎么办?
中断不代表失败,记录下断点原因,次日重新开始,工具会帮你分析断点规律。

3步部署到你的网站

  1. 购买 Hostinger 主机(约¥17/月起,支付宝可付)
  2. 联系 QQ:2445964978,购买后免费获取 习惯打卡追踪器 完整源码
  3. 上传 index.html 到网站目录,访问域名即可直接使用

🎁 购买主机 · 免费领取完整源码

购买 Hostinger 主机后联系我,获取源码打包下载链接

扫码加QQ

📱 QQ:2445964978

📧 [email protected]

📖 完整建站图文教程 →

🚀 立即购买 Hostinger
.section-title-icon { font-size: 1.1rem; } .section-action { font-size: 0.8rem; color: var(--accent); background: none; border: none; cursor: pointer; font-family: inherit; font-weight: 500; } .section-action:hover { text-decoration: underline; } /* Routine */ .routine-header { display: flex; align-items: center; gap: 12px; padding: 14px 20px; background: var(--surface-alt); border-bottom: 1px solid var(--border); cursor: pointer; } .routine-header:hover { background: var(--border); } .routine-expand { font-size: 0.8rem; color: var(--text-muted); transition: transform 0.2s; } .routine-header.collapsed .routine-expand { transform: rotate(-90deg); } .routine-name { font-weight: 600; flex: 1; } .routine-progress { font-size: 0.8rem; color: var(--text-muted); display: flex; align-items: center; gap: 8px; } .routine-progress-bar { width: 60px; height: 6px; background: var(--border); border-radius: 3px; overflow: hidden; } .routine-progress-fill { height: 100%; background: var(--success); border-radius: 3px; } .routine-habits.collapsed { display: none; } /* Habit List */ .habit-item { display: grid; grid-template-columns: 48px 1fr auto; gap: 16px; padding: 14px 20px; border-bottom: 1px solid var(--border); align-items: center; transition: background 0.1s; } .habit-item:last-child { border-bottom: none; } .habit-item:hover { background: var(--surface-alt); } .habit-item.selected { background: var(--accent-light); } .habit-item.needs-attention { } .habit-check { width: 48px; height: 48px; border-radius: 12px; border: 2px solid var(--border); background: var(--surface); display: flex; align-items: center; justify-content: center; font-size: 1.5rem; cursor: pointer; transition: all 0.15s; position: relative; } .habit-check:hover { border-color: var(--accent); transform: scale(1.05); } .habit-check.done { background: var(--success); border-color: var(--success); color: white; } .habit-check.skipped { background: var(--skip-light); border-color: var(--skip); color: var(--skip); } .habit-check.frozen { background: var(--frozen-light); border-color: var(--frozen); color: var(--frozen); } .habit-check.rest-day { background: var(--surface-alt); border-style: dashed; color: var(--text-faint); } .habit-check-menu { position: absolute; top: 100%; left: 50%; transform: translateX(-50%); margin-top: 8px; background: var(--surface); border: 1px solid var(--border); border-radius: 8px; box-shadow: 0 8px 24px var(--shadow-lg); padding: 6px; display: none; z-index: 50; white-space: nowrap; } .habit-check-menu.show { display: block; } .habit-check-option { display: flex; align-items: center; gap: 8px; padding: 8px 12px; border-radius: 6px; font-size: 0.85rem; cursor: pointer; color: var(--text); border: none; background: none; width: 100%; font-family: inherit; } .habit-check-option:hover { background: var(--surface-alt); } .habit-info { min-width: 0; } .habit-name { font-size: 1rem; font-weight: 500; margin-bottom: 2px; display: flex; align-items: center; gap: 8px; } .habit-name-icon { font-size: 1.1rem; } .habit-intention { font-size: 0.8rem; color: var(--text-muted); font-style: italic; margin-bottom: 4px; } .habit-meta { font-size: 0.8rem; color: var(--text-muted); display: flex; align-items: center; gap: 12px; flex-wrap: wrap; } .habit-streak { display: flex; align-items: center; gap: 4px; color: var(--success); font-weight: 500; } .habit-streak.zero { color: var(--text-faint); } .habit-streak.quiet { display: none; } .habit-actions { display: flex; gap: 8px; opacity: 0; transition: opacity 0.15s; } .habit-item:hover .habit-actions { opacity: 1; } .habit-item.selected .habit-actions { opacity: 1; } .habit-action-btn { width: 32px; height: 32px; border: none; background: var(--surface-alt); color: var(--text-muted); border-radius: 6px; cursor: pointer; font-size: 0.9rem; display: flex; align-items: center; justify-content: center; } .habit-action-btn:hover { background: var(--border); color: var(--text); } /* Gentle Failure Options */ .gentle-options { display: none; grid-template-columns: repeat(3, 1fr); gap: 8px; padding: 12px 20px; background: var(--surface-alt); border-top: 1px solid var(--border); } .gentle-options.show { display: grid; } .gentle-option { padding: 10px 12px; border: 1px solid var(--border); border-radius: 8px; background: var(--surface); color: var(--text-muted); font-size: 0.8rem; cursor: pointer; text-align: center; font-family: inherit; } .gentle-option:hover { border-color: var(--accent); color: var(--accent); } /* Add Habit Row */ .add-habit-row { display: flex; align-items: center; gap: 12px; padding: 16px 20px; background: var(--surface-alt); border-top: 1px solid var(--border); } .add-habit-input { flex: 1; padding: 10px 14px; border: 1px solid var(--border); border-radius: 8px; font-family: inherit; font-size: 0.9rem; background: var(--surface); color: var(--text); } .add-habit-input:focus { outline: none; border-color: var(--accent); } .add-habit-input::placeholder { color: var(--text-faint); } .add-habit-btn { padding: 10px 20px; background: var(--accent); color: white; border: none; border-radius: 8px; font-family: inherit; font-size: 0.9rem; font-weight: 500; cursor: pointer; } .add-habit-btn:hover { background: var(--accent-dark); } /* Year Heatmap */ .heatmap-container { padding: 20px; overflow-x: auto; } .heatmap-header { display: flex; justify-content: space-between; align-items: center; margin-bottom: 16px; } .heatmap-title { font-size: 0.9rem; font-weight: 600; } .heatmap-legend { display: flex; align-items: center; gap: 8px; font-size: 0.7rem; color: var(--text-muted); } .heatmap-legend-scale { display: flex; gap: 2px; } .heatmap-legend-cell { width: 12px; height: 12px; border-radius: 2px; } .heatmap-grid { display: flex; gap: 3px; } .heatmap-week { display: flex; flex-direction: column; gap: 3px; } .heatmap-cell { width: 12px; height: 12px; border-radius: 2px; background: var(--surface-alt); border: 1px solid var(--border); cursor: pointer; position: relative; } .heatmap-cell:hover { transform: scale(1.3); z-index: 10; } .heatmap-cell.level-1 { background: var(--success-light); border-color: var(--success-light); } .heatmap-cell.level-2 { background: #6ee7b7; border-color: #6ee7b7; } .heatmap-cell.level-3 { background: #34d399; border-color: #34d399; } .heatmap-cell.level-4 { background: var(--success); border-color: var(--success); } .heatmap-cell.today { box-shadow: 0 0 0 2px var(--accent); } .heatmap-tooltip { position: absolute; bottom: 100%; left: 50%; transform: translateX(-50%); background: var(--text); color: var(--bg); font-size: 0.65rem; padding: 4px 8px; border-radius: 4px; white-space: nowrap; opacity: 0; pointer-events: none; margin-bottom: 4px; z-index: 100; } .heatmap-cell:hover .heatmap-tooltip { opacity: 1; } /* Weekly Review */ .weekly-review { padding: 20px; } .weekly-stats { display: grid; grid-template-columns: repeat(3, 1fr); gap: 16px; margin-bottom: 20px; } .weekly-stats.quiet { display: none; } .weekly-stat { text-align: center; padding: 16px; background: var(--surface-alt); border-radius: 10px; } .weekly-stat-value { font-family: 'IBM Plex Mono', monospace; font-size: 1.5rem; font-weight: 600; color: var(--accent); } .weekly-stat-label { font-size: 0.75rem; color: var(--text-muted); margin-top: 4px; } .weekly-habit { display: flex; align-items: center; gap: 12px; padding: 10px 0; border-bottom: 1px solid var(--border); } .weekly-habit:last-child { border-bottom: none; } .weekly-habit-name { flex: 1; font-size: 0.9rem; font-weight: 500; display: flex; align-items: center; gap: 8px; } .weekly-habit-dots { display: flex; gap: 4px; } .weekly-dot { width: 24px; height: 24px; border-radius: 6px; background: var(--surface-alt); border: 1px solid var(--border); display: flex; align-items: center; justify-content: center; font-size: 0.7rem; color: var(--text-faint); } .weekly-dot.done { background: var(--success); border-color: var(--success); color: white; } .weekly-dot.skipped { background: var(--skip-light); border-color: var(--skip); color: var(--skip); } .weekly-dot.frozen { background: var(--frozen-light); border-color: var(--frozen); color: var(--frozen); } /* Reflection */ .reflection-prompt { background: var(--accent-light); border: 1px solid var(--accent); border-radius: 12px; padding: 20px; margin-bottom: 24px; } .reflection-prompt.hidden { display: none; } .reflection-prompt-title { font-size: 0.95rem; font-weight: 600; margin-bottom: 8px; color: var(--accent); } .reflection-prompt-text { font-size: 0.9rem; color: var(--text-muted); margin-bottom: 16px; } .reflection-textarea { width: 100%; padding: 12px 14px; border: 1px solid var(--border); border-radius: 8px; font-family: inherit; font-size: 0.9rem; background: var(--surface); color: var(--text); resize: vertical; min-height: 80px; } .reflection-textarea:focus { outline: none; border-color: var(--accent); } .reflection-actions { display: flex; gap: 8px; margin-top: 12px; } /* Notes Timeline */ .notes-timeline { padding: 20px; } .note-item { display: flex; gap: 16px; padding: 14px 0; border-bottom: 1px solid var(--border); } .note-item:last-child { border-bottom: none; } .note-date { font-size: 0.75rem; color: var(--text-muted); min-width: 80px; font-family: 'IBM Plex Mono', monospace; } .note-habit { display: flex; align-items: center; gap: 6px; font-size: 0.85rem; font-weight: 500; min-width: 120px; } .note-text { font-size: 0.9rem; color: var(--text); flex: 1; font-style: italic; } /* Data Ownership Panel */ .data-panel { background: var(--surface); border: 1px solid var(--border); border-radius: 12px; padding: 20px; margin-bottom: 24px; } .data-panel-title { font-size: 0.95rem; font-weight: 600; margin-bottom: 16px; } .data-panel-info { font-size: 0.85rem; color: var(--text-muted); margin-bottom: 16px; padding: 12px; background: var(--surface-alt); border-radius: 8px; } .data-panel-actions { display: flex; gap: 12px; flex-wrap: wrap; } /* Quiet Mode Toggle */ .quiet-toggle { display: flex; align-items: center; gap: 12px; padding: 14px 20px; background: var(--surface-alt); border-bottom: 1px solid var(--border); } .quiet-toggle-label { flex: 1; } .quiet-toggle-title { font-size: 0.9rem; font-weight: 500; } .quiet-toggle-sub { font-size: 0.75rem; color: var(--text-muted); } .toggle-switch { width: 44px; height: 24px; background: var(--border); border-radius: 12px; position: relative; cursor: pointer; transition: background 0.2s; } .toggle-switch.active { background: var(--accent); } .toggle-switch::after { content: ''; position: absolute; top: 2px; left: 2px; width: 20px; height: 20px; background: white; border-radius: 50%; transition: transform 0.2s; } .toggle-switch.active::after { transform: translateX(20px); } /* Empty State */ .empty-state { padding: 48px 24px; text-align: center; color: var(--text-muted); } .empty-state-icon { font-size: 3rem; margin-bottom: 16px; opacity: 0.5; } .empty-state-text { margin-bottom: 16px; font-size: 0.95rem; } /* Modals */ .modal-overlay { position: fixed; inset: 0; background: rgba(0,0,0,0.5); z-index: 900; display: none; align-items: center; justify-content: center; padding: 24px; } .modal-overlay.active { display: flex; } .modal { background: var(--surface); border-radius: 16px; width: 100%; max-width: 480px; max-height: 90vh; overflow-y: auto; } .modal-header { padding: 20px; border-bottom: 1px solid var(--border); display: flex; justify-content: space-between; align-items: center; } .modal-title { font-size: 1.1rem; font-weight: 600; } .modal-close { background: none; border: none; font-size: 1.5rem; color: var(--text-muted); cursor: pointer; } .modal-body { padding: 20px; } .form-group { margin-bottom: 18px; } .form-label { display: block; font-size: 0.8rem; font-weight: 500; color: var(--text-muted); margin-bottom: 8px; } .form-input { width: 100%; padding: 12px 14px; border: 1px solid var(--border); border-radius: 8px; font-family: inherit; font-size: 0.95rem; background: var(--bg); color: var(--text); } .form-input:focus { outline: none; border-color: var(--accent); } .form-row { display: grid; grid-template-columns: 1fr 1fr; gap: 12px; } .form-hint { font-size: 0.75rem; color: var(--text-faint); margin-top: 6px; } .frequency-options { display: flex; gap: 8px; flex-wrap: wrap; } .frequency-option { padding: 8px 14px; border: 1px solid var(--border); border-radius: 8px; font-size: 0.85rem; cursor: pointer; background: var(--surface); color: var(--text-muted); font-family: inherit; } .frequency-option:hover { border-color: var(--accent); } .frequency-option.active { background: var(--accent-light); border-color: var(--accent); color: var(--accent); font-weight: 500; } .day-selector { display: flex; gap: 6px; margin-top: 12px; } .day-btn { width: 36px; height: 36px; border-radius: 8px; border: 1px solid var(--border); background: var(--surface); color: var(--text-muted); font-size: 0.75rem; cursor: pointer; font-family: inherit; } .day-btn:hover { border-color: var(--accent); } .day-btn.active { background: var(--accent-light); border-color: var(--accent); color: var(--accent); } .day-btn.rest { background: var(--skip-light); border-color: var(--skip); color: var(--skip); } .icon-picker { display: grid; grid-template-columns: repeat(8, 1fr); gap: 8px; } .icon-option { aspect-ratio: 1; border: 1px solid var(--border); border-radius: 8px; font-size: 1.25rem; cursor: pointer; background: var(--surface); display: flex; align-items: center; justify-content: center; } .icon-option:hover { border-color: var(--accent); background: var(--accent-light); } .icon-option.active { border-color: var(--accent); background: var(--accent-light); } .modal-footer { padding: 16px 20px; border-top: 1px solid var(--border); display: flex; justify-content: flex-end; gap: 10px; } .btn { padding: 10px 20px; border-radius: 8px; font-family: inherit; font-size: 0.9rem; font-weight: 500; cursor: pointer; border: 1px solid var(--border); background: var(--surface); color: var(--text); } .btn:hover { background: var(--surface-alt); } .btn-primary { background: var(--accent); color: white; border: none; } .btn-primary:hover { background: var(--accent-dark); } .btn-danger { background: var(--danger); color: white; border: none; } .btn-sm { padding: 8px 14px; font-size: 0.8rem; } /* Toast */ .toast { position: fixed; bottom: 24px; right: 24px; background: var(--text); color: var(--bg); padding: 14px 20px; border-radius: 10px; font-size: 0.9rem; display: flex; align-items: center; gap: 12px; opacity: 0; transform: translateY(8px); transition: all 0.2s; z-index: 1000; } .toast.show { opacity: 1; transform: translateY(0); } .toast-undo { background: var(--accent); color: white; border: none; padding: 6px 12px; border-radius: 6px; font-size: 0.8rem; font-family: inherit; cursor: pointer; } /* Footer */ .app-footer { text-align: center; padding: 24px; font-size: 0.75rem; color: var(--text-faint); border-top: 1px solid var(--border); margin-top: 48px; } .app-footer-philosophy { margin-bottom: 8px; font-style: italic; } /* Mobile */ @media (max-width: 768px) { .sidebar { display: none; } .main-wrapper { margin-left: 0 !important; } .app-header { padding: 0 16px; } .container { padding: 20px 16px; } .stats-row { grid-template-columns: repeat(2, 1fr); gap: 12px; } .habit-item { grid-template-columns: 40px 1fr auto; gap: 12px; padding: 12px 16px; } .habit-check { width: 40px; height: 40px; font-size: 1.25rem; } .habit-actions { opacity: 1; } .weekly-stats { grid-template-columns: 1fr; } .icon-picker { grid-template-columns: repeat(6, 1fr); } .gentle-options { grid-template-columns: 1fr; } } @media print { .sidebar, .app-header, .add-habit-row, .toast, .modal-overlay, .habit-actions, .section-action, .philosophy-screen { display: none !important; } .main-wrapper { margin-left: 0 !important; } }

Streak

A calmer way to build habits.

🚫
No goals to hit
Just show up. That's enough.
🤍
No streak shame
Missing days is editing, not failure.
No dashboards to maintain
Your data stays here. No cloud. No account.
Today
0
Completed
0
Remaining
0
Best Streak
0
Total
Quiet Mode
Hide streaks and stats
📋 Today's Habits
Saved