Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
89 changes: 89 additions & 0 deletions css/planner.css
Original file line number Diff line number Diff line change
@@ -0,0 +1,89 @@
/* Smart Study Planner Styles */

.streak-widget {
color: var(--color-text-warning);
}

.session-block {
background: var(--color-background-primary);
border: 1px solid var(--color-border-primary);
border-left: 4px solid var(--color-text-info);
border-radius: 8px;
padding: 16px;
display: flex;
justify-content: space-between;
align-items: center;
transition: transform 0.2s, box-shadow 0.2s;
}

.session-block:hover {
transform: translateY(-2px);
box-shadow: var(--shadow-sm);
}

.session-block.completed {
opacity: 0.6;
border-left-color: var(--color-text-success);
}

.session-block.completed .session-title {
text-decoration: line-through;
color: var(--color-text-tertiary);
}

.session-info {
display: flex;
flex-direction: column;
gap: 4px;
}

.session-title {
font-weight: 600;
font-size: 16px;
color: var(--color-text-primary);
}

.session-meta {
font-size: 13px;
color: var(--color-text-secondary);
display: flex;
gap: 12px;
}

.session-type-badge {
background: var(--color-background-secondary);
padding: 2px 8px;
border-radius: 12px;
font-size: 11px;
text-transform: uppercase;
font-weight: 700;
letter-spacing: 0.05em;
}

.session-type-revision {
color: var(--color-text-warning);
background: rgba(234, 179, 8, 0.1);
}

.session-type-learning {
color: var(--color-text-info);
background: rgba(59, 130, 246, 0.1);
}

.exam-item, .goal-item {
background: var(--color-background-secondary);
padding: 12px;
border-radius: 8px;
border: 1px solid var(--color-border-secondary);
}

.exam-title, .goal-title {
font-weight: 600;
font-size: 14px;
margin-bottom: 4px;
}

.exam-meta, .goal-meta {
font-size: 12px;
color: var(--color-text-tertiary);
}
33 changes: 33 additions & 0 deletions database.js
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,39 @@ function initDb() {
}
});

// Exams Table
db.run(`CREATE TABLE IF NOT EXISTS exams (
id TEXT PRIMARY KEY,
subject_id TEXT,
title TEXT NOT NULL,
date DATETIME NOT NULL,
created_at DATETIME DEFAULT CURRENT_TIMESTAMP,
FOREIGN KEY (subject_id) REFERENCES subjects(id)
)`);

// Study Goals Table
db.run(`CREATE TABLE IF NOT EXISTS study_goals (
id TEXT PRIMARY KEY,
subject_id TEXT,
description TEXT NOT NULL,
target_date DATETIME,
created_at DATETIME DEFAULT CURRENT_TIMESTAMP,
FOREIGN KEY (subject_id) REFERENCES subjects(id)
)`);

// Study Sessions Table
db.run(`CREATE TABLE IF NOT EXISTS study_sessions (
id TEXT PRIMARY KEY,
subject_id TEXT,
title TEXT NOT NULL,
start_time DATETIME NOT NULL,
end_time DATETIME NOT NULL,
status TEXT DEFAULT 'pending',
type TEXT DEFAULT 'learning',
created_at DATETIME DEFAULT CURRENT_TIMESTAMP,
FOREIGN KEY (subject_id) REFERENCES subjects(id)
)`);

// Pre-populate some subjects if empty
db.get('SELECT COUNT(*) as count FROM subjects', (err, row) => {
if (row && row.count === 0) {
Expand Down
160 changes: 151 additions & 9 deletions index.html
Original file line number Diff line number Diff line change
@@ -1,12 +1,41 @@
<!DOCTYPE html>
<html lang="en">
<head>
<script>
window.onerror = function(message, source, lineno, colno, error) {
const errDiv = document.createElement('div');
errDiv.style.position = 'fixed';
errDiv.style.top = '0';
errDiv.style.left = '0';
errDiv.style.width = '100%';
errDiv.style.background = 'red';
errDiv.style.color = 'white';
errDiv.style.padding = '10px';
errDiv.style.zIndex = '999999';
errDiv.innerHTML = `<strong>Error:</strong> ${message} at ${source}:${lineno}:${colno}`;
document.body.appendChild(errDiv);
};
window.addEventListener('unhandledrejection', function(event) {
const errDiv = document.createElement('div');
errDiv.style.position = 'fixed';
errDiv.style.top = '40px';
errDiv.style.left = '0';
errDiv.style.width = '100%';
errDiv.style.background = 'orange';
errDiv.style.color = 'white';
errDiv.style.padding = '10px';
errDiv.style.zIndex = '999999';
errDiv.innerHTML = `<strong>Unhandled Promise Rejection:</strong> ${event.reason}`;
document.body.appendChild(errDiv);
});
</script>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>StudyPlan</title>
<link rel="stylesheet" href="/css/index.css">
<link rel="stylesheet" href="/css/planner.css">

<script src="https://cdn.jsdelivr.net/npm/canvas-confetti@1.9.3/dist/confetti.browser.min.js"></script>
<script src="/js/confetti.browser.min.js"></script>

<link rel="icon" type="image/x-icon" href="/favicon.ico" />
<link href="https://fonts.googleapis.com/css2?family=Inter:wght@400;500;600;700&display=swap" rel="stylesheet">
Expand Down Expand Up @@ -78,6 +107,10 @@ <h1 class="site-title">StudyPlan</h1>
<svg width="16" height="16" viewBox="0 0 16 16" fill="none" aria-hidden="true"><rect x="1" y="2" width="14" height="13" rx="2" stroke="currentColor" stroke-width="1.5"/><path d="M1 6h14" stroke="currentColor" stroke-width="1.5"/><path d="M5 1v2M11 1v2" stroke="currentColor" stroke-width="1.5" stroke-linecap="round"/></svg>
Calendar
</div>
<div class="nav-item" id="planner-nav-btn" role="link" aria-label="Smart Planner">
<svg width="16" height="16" viewBox="0 0 16 16" fill="none" aria-hidden="true"><path d="M8 2l2 4 4 1-3 3 1 4-4-2-4 2 1-4-3-3 4-1z" stroke="currentColor" stroke-width="1.5" stroke-linejoin="round"/></svg>
Smart Planner
</div>
<div class="nav-item" id="all-tasks-btn" role="link" aria-label="View All Tasks">
<svg width="16" height="16" viewBox="0 0 16 16" fill="none" aria-hidden="true"><path d="M2 4h12M2 8h9M2 12h6" stroke="currentColor" stroke-width="1.5" stroke-linecap="round"/></svg>
All Tasks
Expand Down Expand Up @@ -110,8 +143,8 @@ <h1 class="site-title">StudyPlan</h1>
</div>
</div>

<!-- Main -->
<div class="main">
<!-- Main Tasks View -->
<div class="main" id="tasks-view">
<div class="topbar">
<div class="topbar-title">April 2026</div>
<select id="label-filter" style="margin-left:auto; margin-right: 12px; padding: 6px; border-radius: 6px; border: 1px solid var(--color-border-secondary); background: var(--color-background-primary); color: var(--color-text-primary); outline: none; cursor: pointer;">
Expand Down Expand Up @@ -233,15 +266,84 @@ <h1 class="site-title">StudyPlan</h1>
</div>
<div id="summary-box" class="summary-box"></div>

<button id="add-btn" class="add-btn" disabled>
Add items to planner
</button>
</div>


<button id="add-btn" class="add-btn" disabled>Add items to planner</button>
</div>

</div>
</div>

<!-- Planner View -->
<div class="main" id="planner-view" style="display:none; padding: 24px; flex-direction: column; gap: 24px; overflow-y: auto;">

<!-- Top header for Planner -->
<div style="display: flex; justify-content: space-between; align-items: center;">
<h2 style="font-size: 24px; font-weight: 700; margin: 0;">AI Study Planner</h2>
<div style="display: flex; gap: 12px;">
<div class="streak-widget" style="background: var(--color-background-secondary); padding: 8px 12px; border-radius: 8px; font-weight: 600; display: flex; align-items: center; gap: 8px;">
🔥 Streak: <span id="streak-count">0</span> days
</div>
<button class="btn btn-primary" id="generate-schedule-btn">
✨ Generate Smart Schedule
</button>
</div>
</div>

<!-- Main Layout: Sidebar (Exams/Goals/Pomodoro) + Timeline -->
<div style="display: flex; gap: 24px; flex-wrap: wrap;">

<!-- Planner Sidebar -->
<div style="flex: 1; min-width: 300px; display: flex; flex-direction: column; gap: 24px;">

<!-- Pomodoro Widget -->
<div class="panel" style="padding: 24px; text-align: center;">
<h3 style="margin-top: 0; color: var(--color-text-primary);">Pomodoro Timer</h3>
<div id="pomodoro-time" style="font-size: 48px; font-weight: 700; font-variant-numeric: tabular-nums; margin: 16px 0; color: var(--color-text-primary);">25:00</div>
<div style="display: flex; justify-content: center; gap: 8px;">
<button class="btn btn-primary" id="pomodoro-start">Start</button>
<button class="btn" id="pomodoro-pause">Pause</button>
<button class="btn" id="pomodoro-reset">Reset</button>
</div>
<div style="margin-top: 12px; font-size: 13px; color: var(--color-text-tertiary);">
<span id="pomodoro-mode">Focus Mode</span>
</div>
</div>

<!-- Exams -->
<div class="panel">
<div class="panel-header" style="padding: 16px; display: flex; justify-content: space-between;">
<div class="panel-title">Upcoming Exams</div>
<button class="btn" id="add-exam-btn" style="padding: 4px 8px; font-size: 12px;">+ Add</button>
</div>
<div id="exam-list" style="padding: 0 16px 16px; display:flex; flex-direction:column; gap:8px;">
<!-- JS injected -->
</div>
</div>

<!-- Goals -->
<div class="panel">
<div class="panel-header" style="padding: 16px; display: flex; justify-content: space-between;">
<div class="panel-title">Study Goals</div>
<button class="btn" id="add-goal-btn" style="padding: 4px 8px; font-size: 12px;">+ Add</button>
</div>
<div id="goal-list" style="padding: 0 16px 16px; display:flex; flex-direction:column; gap:8px;">
<!-- JS injected -->
</div>
</div>

</div>

<!-- Schedule Timeline -->
<div class="panel" style="flex: 2; min-width: 400px; padding: 24px;">
<h3 style="margin-top: 0; margin-bottom: 24px;">Your Study Schedule</h3>
<div id="schedule-timeline" style="display: flex; flex-direction: column; gap: 16px;">
<div style="text-align: center; color: var(--color-text-tertiary); padding: 40px;">
Click "Generate Smart Schedule" to let AI plan your studies.
</div>
</div>
</div>

</div>
</div>
</div>

<footer class="site-footer">
Expand Down Expand Up @@ -513,5 +615,45 @@ <h3 style="margin:0 0 12px; font-size:18px; font-weight:600;">New task</h3>
</div>
</div>
</div>

<div id="new-exam-modal" class="modal-backdrop" style="display:none; position:fixed; inset:0; z-index:9998; align-items:center; justify-content:center;">
<div class="modal-card" style=" border-radius:12px; padding:20px; width:320px; box-shadow:0 12px 40px rgba(0,0,0,0.25);">
<h3 style="margin:0 0 12px; font-size:18px; font-weight:600;">New Exam</h3>

<label style="display:block; font-size:12px; margin-bottom:4px;">Exam Name</label>
<input id="new-exam-title" type="text" style="width:100%; padding:6px; margin-bottom:10px;" placeholder="e.g. Final OS Exam">

<label style="display:block; font-size:12px; margin-bottom:4px;">Subject</label>
<select id="new-exam-subject" style="width:100%; padding:6px; margin-bottom:10px;"></select>

<label style="display:block; font-size:12px; margin-bottom:4px;">Exam Date</label>
<input id="new-exam-date" type="date" style="width:100%; padding:6px; margin-bottom:16px;">

<div style="display:flex; justify-content:flex-end; gap:8px;">
<button id="new-exam-cancel" class="btn" style="padding:6px 10px;">Cancel</button>
<button id="new-exam-save" class="btn btn-primary" style="padding:6px 12px;">Save</button>
</div>
</div>
</div>

<div id="new-goal-modal" class="modal-backdrop" style="display:none; position:fixed; inset:0; z-index:9998; align-items:center; justify-content:center;">
<div class="modal-card" style=" border-radius:12px; padding:20px; width:320px; box-shadow:0 12px 40px rgba(0,0,0,0.25);">
<h3 style="margin:0 0 12px; font-size:18px; font-weight:600;">New Study Goal</h3>

<label style="display:block; font-size:12px; margin-bottom:4px;">Goal Description</label>
<input id="new-goal-desc" type="text" style="width:100%; padding:6px; margin-bottom:10px;" placeholder="e.g. Master dynamic programming">

<label style="display:block; font-size:12px; margin-bottom:4px;">Subject</label>
<select id="new-goal-subject" style="width:100%; padding:6px; margin-bottom:10px;"></select>

<label style="display:block; font-size:12px; margin-bottom:4px;">Target Date</label>
<input id="new-goal-date" type="date" style="width:100%; padding:6px; margin-bottom:16px;">

<div style="display:flex; justify-content:flex-end; gap:8px;">
<button id="new-goal-cancel" class="btn" style="padding:6px 10px;">Cancel</button>
<button id="new-goal-save" class="btn btn-primary" style="padding:6px 12px;">Save</button>
</div>
</div>
</div>
</body>
</html>
4 changes: 3 additions & 1 deletion js/app.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ import { extractTasksFromText } from './utils/api.js';
import { initGlobalErrorBoundary } from './utils/errorBoundary.js';
import { analyzeWorkload } from './utils/scheduler.js';
import { Toast } from './utils/toast.js';
import { initPlanner } from './planner.js';

initGlobalErrorBoundary();

Expand Down Expand Up @@ -1028,6 +1029,7 @@ store.subscribe(renderFocusTasks);
store.subscribe(renderSidebarSubjects);

document.addEventListener('DOMContentLoaded', () => {
initPlanner();
if (newSubjectColorsEl) {
SUBJECT_COLORS.forEach(c => {
const btn = document.createElement('button');
Expand Down Expand Up @@ -1381,7 +1383,7 @@ if (quoteEl) {
quoteEl.textContent = quotes[index];
}

const calendarDownloadBtn = document.getElementById('calendar-download-btn');
calendarDownloadBtn = document.getElementById('calendar-download-btn');

if (calendarDownloadBtn) {
calendarDownloadBtn.addEventListener('click', () => {
Expand Down
Loading