first commit
This commit is contained in:
0
src/web/__init__.py
Normal file
0
src/web/__init__.py
Normal file
0
src/web/static/__init__.py
Normal file
0
src/web/static/__init__.py
Normal file
0
src/web/static/css/__init__.py
Normal file
0
src/web/static/css/__init__.py
Normal file
299
src/web/static/css/style.css
Normal file
299
src/web/static/css/style.css
Normal file
@@ -0,0 +1,299 @@
|
||||
/* MyOrg Assistant Styles */
|
||||
|
||||
* {
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
box-sizing: border-box;
|
||||
}
|
||||
|
||||
:root {
|
||||
--primary: #2563eb;
|
||||
--secondary: #64748b;
|
||||
--success: #10b981;
|
||||
--warning: #f59e0b;
|
||||
--danger: #ef4444;
|
||||
--bg: #f8fafc;
|
||||
--surface: #ffffff;
|
||||
--text: #1e293b;
|
||||
--text-muted: #64748b;
|
||||
--border: #e2e8f0;
|
||||
}
|
||||
|
||||
body {
|
||||
font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, sans-serif;
|
||||
background: var(--bg);
|
||||
color: var(--text);
|
||||
line-height: 1.6;
|
||||
}
|
||||
|
||||
/* Navigation */
|
||||
.navbar {
|
||||
background: var(--surface);
|
||||
border-bottom: 1px solid var(--border);
|
||||
padding: 1rem 2rem;
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.nav-brand h1 {
|
||||
font-size: 1.5rem;
|
||||
color: var(--primary);
|
||||
}
|
||||
|
||||
.nav-links {
|
||||
display: flex;
|
||||
gap: 1.5rem;
|
||||
}
|
||||
|
||||
.nav-links a {
|
||||
text-decoration: none;
|
||||
color: var(--text-muted);
|
||||
font-weight: 500;
|
||||
transition: color 0.2s;
|
||||
}
|
||||
|
||||
.nav-links a:hover,
|
||||
.nav-links a.active {
|
||||
color: var(--primary);
|
||||
}
|
||||
|
||||
/* Container */
|
||||
.container {
|
||||
max-width: 1200px;
|
||||
margin: 2rem auto;
|
||||
padding: 0 2rem;
|
||||
}
|
||||
|
||||
/* Dashboard */
|
||||
.dashboard-header {
|
||||
margin-bottom: 2rem;
|
||||
}
|
||||
|
||||
.date {
|
||||
color: var(--text-muted);
|
||||
font-size: 0.95rem;
|
||||
}
|
||||
|
||||
.stats-grid {
|
||||
display: grid;
|
||||
grid-template-columns: repeat(auto-fit, minmax(200px, 1fr));
|
||||
gap: 1rem;
|
||||
margin-bottom: 2rem;
|
||||
}
|
||||
|
||||
.stat-card {
|
||||
background: var(--surface);
|
||||
padding: 1.5rem;
|
||||
border-radius: 8px;
|
||||
border: 1px solid var(--border);
|
||||
}
|
||||
|
||||
.stat-value {
|
||||
font-size: 2rem;
|
||||
font-weight: bold;
|
||||
color: var(--primary);
|
||||
}
|
||||
|
||||
.stat-label {
|
||||
color: var(--text-muted);
|
||||
font-size: 0.9rem;
|
||||
margin-top: 0.5rem;
|
||||
}
|
||||
|
||||
.dashboard-grid {
|
||||
display: grid;
|
||||
grid-template-columns: repeat(auto-fit, minmax(300px, 1fr));
|
||||
gap: 1.5rem;
|
||||
}
|
||||
|
||||
.dashboard-section {
|
||||
background: var(--surface);
|
||||
padding: 1.5rem;
|
||||
border-radius: 8px;
|
||||
border: 1px solid var(--border);
|
||||
}
|
||||
|
||||
.dashboard-section h3 {
|
||||
margin-bottom: 1rem;
|
||||
color: var(--text);
|
||||
}
|
||||
|
||||
.empty-state {
|
||||
color: var(--text-muted);
|
||||
font-style: italic;
|
||||
}
|
||||
|
||||
/* Task Items */
|
||||
.task-list, .event-list, .project-list {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 0.75rem;
|
||||
}
|
||||
|
||||
.task-item, .event-item, .project-item {
|
||||
padding: 0.75rem;
|
||||
background: var(--bg);
|
||||
border-radius: 4px;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 0.5rem;
|
||||
flex-wrap: wrap;
|
||||
}
|
||||
|
||||
.priority-badge {
|
||||
background: var(--warning);
|
||||
color: white;
|
||||
padding: 0.25rem 0.5rem;
|
||||
border-radius: 4px;
|
||||
font-size: 0.85rem;
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
.priority-A { background: var(--danger); }
|
||||
.priority-B { background: var(--warning); }
|
||||
.priority-C { background: var(--secondary); }
|
||||
|
||||
.tag {
|
||||
background: var(--primary);
|
||||
color: white;
|
||||
padding: 0.25rem 0.5rem;
|
||||
border-radius: 4px;
|
||||
font-size: 0.85rem;
|
||||
}
|
||||
|
||||
.tag.context {
|
||||
background: var(--success);
|
||||
}
|
||||
|
||||
.tag.project {
|
||||
background: var(--primary);
|
||||
}
|
||||
|
||||
.due-date {
|
||||
color: var(--warning);
|
||||
font-size: 0.9rem;
|
||||
margin-left: auto;
|
||||
}
|
||||
|
||||
.event-time {
|
||||
font-weight: 600;
|
||||
color: var(--primary);
|
||||
min-width: 60px;
|
||||
}
|
||||
|
||||
.project-tag {
|
||||
font-weight: 600;
|
||||
color: var(--primary);
|
||||
}
|
||||
|
||||
/* Chat */
|
||||
.chat-container {
|
||||
max-width: 800px;
|
||||
margin: 0 auto;
|
||||
}
|
||||
|
||||
.chat-messages {
|
||||
background: var(--surface);
|
||||
border: 1px solid var(--border);
|
||||
border-radius: 8px;
|
||||
padding: 1rem;
|
||||
height: 500px;
|
||||
overflow-y: auto;
|
||||
margin-bottom: 1rem;
|
||||
}
|
||||
|
||||
.message {
|
||||
margin-bottom: 1rem;
|
||||
padding: 0.75rem;
|
||||
border-radius: 4px;
|
||||
}
|
||||
|
||||
.message.assistant {
|
||||
background: var(--bg);
|
||||
}
|
||||
|
||||
.message.user {
|
||||
background: var(--primary);
|
||||
color: white;
|
||||
margin-left: 20%;
|
||||
}
|
||||
|
||||
.chat-form {
|
||||
display: flex;
|
||||
gap: 0.5rem;
|
||||
margin-bottom: 1rem;
|
||||
}
|
||||
|
||||
.chat-form input {
|
||||
flex: 1;
|
||||
padding: 0.75rem;
|
||||
border: 1px solid var(--border);
|
||||
border-radius: 4px;
|
||||
font-size: 1rem;
|
||||
}
|
||||
|
||||
.chat-form button {
|
||||
padding: 0.75rem 1.5rem;
|
||||
background: var(--primary);
|
||||
color: white;
|
||||
border: none;
|
||||
border-radius: 4px;
|
||||
cursor: pointer;
|
||||
font-weight: 600;
|
||||
}
|
||||
|
||||
.chat-form button:hover {
|
||||
opacity: 0.9;
|
||||
}
|
||||
|
||||
/* Buttons */
|
||||
.btn-link {
|
||||
color: var(--primary);
|
||||
text-decoration: none;
|
||||
font-size: 0.9rem;
|
||||
margin-top: 0.5rem;
|
||||
display: inline-block;
|
||||
}
|
||||
|
||||
.btn-secondary {
|
||||
background: var(--secondary);
|
||||
color: white;
|
||||
padding: 0.5rem 1rem;
|
||||
border: none;
|
||||
border-radius: 4px;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.btn-secondary:hover {
|
||||
opacity: 0.9;
|
||||
}
|
||||
|
||||
/* Footer */
|
||||
footer {
|
||||
text-align: center;
|
||||
padding: 2rem;
|
||||
color: var(--text-muted);
|
||||
font-size: 0.9rem;
|
||||
}
|
||||
|
||||
/* Responsive */
|
||||
@media (max-width: 768px) {
|
||||
.navbar {
|
||||
flex-direction: column;
|
||||
gap: 1rem;
|
||||
}
|
||||
|
||||
.nav-links {
|
||||
flex-wrap: wrap;
|
||||
justify-content: center;
|
||||
}
|
||||
|
||||
.dashboard-grid {
|
||||
grid-template-columns: 1fr;
|
||||
}
|
||||
|
||||
.stats-grid {
|
||||
grid-template-columns: repeat(2, 1fr);
|
||||
}
|
||||
}
|
||||
0
src/web/static/js/__init__.py
Normal file
0
src/web/static/js/__init__.py
Normal file
0
src/web/templates/__init__.py
Normal file
0
src/web/templates/__init__.py
Normal file
35
src/web/templates/base.html
Normal file
35
src/web/templates/base.html
Normal file
@@ -0,0 +1,35 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<title>{% block title %}MyOrg Assistant{% endblock %}</title>
|
||||
<link rel="stylesheet" href="/static/css/style.css">
|
||||
<script src="https://unpkg.com/htmx.org@1.9.10"></script>
|
||||
{% block extra_head %}{% endblock %}
|
||||
</head>
|
||||
<body>
|
||||
<nav class="navbar">
|
||||
<div class="nav-brand">
|
||||
<h1>🤖 MyOrg Assistant</h1>
|
||||
</div>
|
||||
<div class="nav-links">
|
||||
<a href="/dashboard" class="{% if page == 'dashboard' %}active{% endif %}">📊 Dashboard</a>
|
||||
<a href="/chat" class="{% if page == 'chat' %}active{% endif %}">💬 Chat</a>
|
||||
<a href="/tasks" class="{% if page == 'tasks' %}active{% endif %}">✅ Tasks</a>
|
||||
<a href="/calendar" class="{% if page == 'calendar' %}active{% endif %}">📅 Calendar</a>
|
||||
<a href="/projects" class="{% if page == 'projects' %}active{% endif %}">📂 Projects</a>
|
||||
</div>
|
||||
</nav>
|
||||
|
||||
<main class="container">
|
||||
{% block content %}{% endblock %}
|
||||
</main>
|
||||
|
||||
<footer>
|
||||
<p>MyOrg Assistant - Powered by Claude Sonnet 4.5</p>
|
||||
</footer>
|
||||
|
||||
{% block extra_scripts %}{% endblock %}
|
||||
</body>
|
||||
</html>
|
||||
23
src/web/templates/calendar.html
Normal file
23
src/web/templates/calendar.html
Normal file
@@ -0,0 +1,23 @@
|
||||
{% extends "base.html" %}
|
||||
{% block title %}Calendar - MyOrg Assistant{% endblock %}
|
||||
{% block content %}
|
||||
<h2>📅 Calendar</h2>
|
||||
<h3>Today - {{ today }}</h3>
|
||||
<div class="event-list">
|
||||
{% for event in today_events %}
|
||||
<div class="event-item">
|
||||
<span class="event-time">{% if event.time %}{{ event.time.strftime('%H:%M') }}{% else %}All day{% endif %}</span>
|
||||
{{ event.description }}
|
||||
</div>
|
||||
{% endfor %}
|
||||
</div>
|
||||
<h3>Upcoming (Next 7 Days)</h3>
|
||||
<div class="event-list">
|
||||
{% for event in upcoming_events %}
|
||||
<div class="event-item">
|
||||
<span>{{ event.date.strftime('%Y-%m-%d') }} {% if event.time %}{{ event.time.strftime('%H:%M') }}{% endif %}</span>
|
||||
{{ event.description }}
|
||||
</div>
|
||||
{% endfor %}
|
||||
</div>
|
||||
{% endblock %}
|
||||
32
src/web/templates/chat.html
Normal file
32
src/web/templates/chat.html
Normal file
@@ -0,0 +1,32 @@
|
||||
{% extends "base.html" %}
|
||||
|
||||
{% block title %}Chat - MyOrg Assistant{% endblock %}
|
||||
|
||||
{% block content %}
|
||||
<div class="chat-container">
|
||||
<h2>💬 Chat with Assistant</h2>
|
||||
|
||||
<div class="chat-messages" id="messages">
|
||||
<div class="message assistant">
|
||||
<strong>Assistant:</strong> Hi! I'm your MyOrg assistant. Ask me anything about your tasks, calendar, or projects!
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<form class="chat-form" hx-post="/api/chat" hx-target="#messages" hx-swap="beforeend" hx-on::after-request="this.reset()">
|
||||
<input type="text" name="message" placeholder="Type your message..." required autofocus>
|
||||
<button type="submit">Send</button>
|
||||
</form>
|
||||
|
||||
<button hx-post="/api/chat/reset" hx-swap="none" class="btn-secondary">Clear History</button>
|
||||
</div>
|
||||
{% endblock %}
|
||||
|
||||
{% block extra_scripts %}
|
||||
<script>
|
||||
// Auto-scroll to bottom when new messages arrive
|
||||
htmx.on('htmx:afterSwap', function(evt) {
|
||||
var messages = document.getElementById('messages');
|
||||
messages.scrollTop = messages.scrollHeight;
|
||||
});
|
||||
</script>
|
||||
{% endblock %}
|
||||
111
src/web/templates/dashboard.html
Normal file
111
src/web/templates/dashboard.html
Normal file
@@ -0,0 +1,111 @@
|
||||
{% extends "base.html" %}
|
||||
|
||||
{% block title %}Dashboard - MyOrg Assistant{% endblock %}
|
||||
|
||||
{% block content %}
|
||||
<div class="dashboard">
|
||||
<div class="dashboard-header">
|
||||
<h2>📊 Dashboard</h2>
|
||||
<p class="date">{{ today }}</p>
|
||||
</div>
|
||||
|
||||
<div class="stats-grid">
|
||||
<div class="stat-card">
|
||||
<div class="stat-value">{{ stats.events_today }}</div>
|
||||
<div class="stat-label">Events Today</div>
|
||||
</div>
|
||||
<div class="stat-card">
|
||||
<div class="stat-value">{{ stats.priority_tasks }}</div>
|
||||
<div class="stat-label">Priority Tasks</div>
|
||||
</div>
|
||||
<div class="stat-card">
|
||||
<div class="stat-value">{{ stats.due_soon }}</div>
|
||||
<div class="stat-label">Due Soon</div>
|
||||
</div>
|
||||
<div class="stat-card">
|
||||
<div class="stat-value">{{ stats.active_projects }}</div>
|
||||
<div class="stat-label">Active Projects</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="dashboard-grid">
|
||||
<!-- Today's Events -->
|
||||
<div class="dashboard-section">
|
||||
<h3>📅 Today's Schedule</h3>
|
||||
{% if events %}
|
||||
<div class="event-list">
|
||||
{% for event in events %}
|
||||
<div class="event-item">
|
||||
<span class="event-time">
|
||||
{% if event.time %}{{ event.time.strftime('%H:%M') }}{% else %}All day{% endif %}
|
||||
</span>
|
||||
<span class="event-desc">{{ event.description }}</span>
|
||||
{% for context in event.contexts %}
|
||||
<span class="tag context">@{{ context }}</span>
|
||||
{% endfor %}
|
||||
</div>
|
||||
{% endfor %}
|
||||
</div>
|
||||
{% else %}
|
||||
<p class="empty-state">No events scheduled today</p>
|
||||
{% endif %}
|
||||
</div>
|
||||
|
||||
<!-- Priority Tasks -->
|
||||
<div class="dashboard-section">
|
||||
<h3>✅ Priority Tasks</h3>
|
||||
{% if priority_tasks %}
|
||||
<div class="task-list">
|
||||
{% for task in priority_tasks %}
|
||||
<div class="task-item">
|
||||
<span class="priority-badge priority-{{ task.priority }}">{{ task.priority }}</span>
|
||||
<span class="task-desc">{{ task.description }}</span>
|
||||
{% for project in task.projects %}
|
||||
<span class="tag project">+{{ project }}</span>
|
||||
{% endfor %}
|
||||
</div>
|
||||
{% endfor %}
|
||||
</div>
|
||||
<a href="/tasks?priority=A" class="btn-link">View all →</a>
|
||||
{% else %}
|
||||
<p class="empty-state">No priority tasks</p>
|
||||
{% endif %}
|
||||
</div>
|
||||
|
||||
<!-- Due Soon -->
|
||||
<div class="dashboard-section">
|
||||
<h3>⏰ Due Soon</h3>
|
||||
{% if due_soon %}
|
||||
<div class="task-list">
|
||||
{% for task in due_soon %}
|
||||
<div class="task-item">
|
||||
<span class="task-desc">{{ task.description }}</span>
|
||||
<span class="due-date">📅 {{ task.due_date.strftime('%Y-%m-%d') }}</span>
|
||||
</div>
|
||||
{% endfor %}
|
||||
</div>
|
||||
{% else %}
|
||||
<p class="empty-state">Nothing due soon</p>
|
||||
{% endif %}
|
||||
</div>
|
||||
|
||||
<!-- Active Projects -->
|
||||
<div class="dashboard-section">
|
||||
<h3>📂 Active Projects</h3>
|
||||
{% if active_projects %}
|
||||
<div class="project-list">
|
||||
{% for project in active_projects %}
|
||||
<div class="project-item">
|
||||
<span class="project-tag">+{{ project.tag }}</span>
|
||||
<span class="project-desc">{{ project.description }}</span>
|
||||
</div>
|
||||
{% endfor %}
|
||||
</div>
|
||||
<a href="/projects" class="btn-link">View all →</a>
|
||||
{% else %}
|
||||
<p class="empty-state">No active projects</p>
|
||||
{% endif %}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
{% endblock %}
|
||||
16
src/web/templates/projects.html
Normal file
16
src/web/templates/projects.html
Normal file
@@ -0,0 +1,16 @@
|
||||
{% extends "base.html" %}
|
||||
{% block title %}Projects - MyOrg Assistant{% endblock %}
|
||||
{% block content %}
|
||||
<h2>📂 Projects</h2>
|
||||
<p>Active: {{ stats.active }} | Waiting: {{ stats.waiting }} | Someday: {{ stats.someday }}</p>
|
||||
<div class="project-list">
|
||||
{% for project in projects %}
|
||||
<div class="project-item">
|
||||
<strong>+{{ project.tag }}</strong> - {{ project.description }} [{{ project.status }}]
|
||||
{% if project_task_counts.get(project.tag) %}
|
||||
<span class="badge">{{ project_task_counts[project.tag] }} tasks</span>
|
||||
{% endif %}
|
||||
</div>
|
||||
{% endfor %}
|
||||
</div>
|
||||
{% endblock %}
|
||||
17
src/web/templates/tasks.html
Normal file
17
src/web/templates/tasks.html
Normal file
@@ -0,0 +1,17 @@
|
||||
{% extends "base.html" %}
|
||||
{% block title %}Tasks - MyOrg Assistant{% endblock %}
|
||||
{% block content %}
|
||||
<h2>✅ Tasks</h2>
|
||||
<p>Total: {{ total_tasks }} active, {{ completed_tasks }} completed</p>
|
||||
<div class="task-list">
|
||||
{% for task in tasks %}
|
||||
<div class="task-item">
|
||||
<span class="{% if task.priority %}priority-{{ task.priority }}{% endif %}">
|
||||
{% if task.priority %}({{ task.priority }}){% endif %} {{ task.description }}
|
||||
</span>
|
||||
{% for p in task.projects %}<span class="tag">+{{ p }}</span>{% endfor %}
|
||||
{% for c in task.contexts %}<span class="tag">@{{ c }}</span>{% endfor %}
|
||||
</div>
|
||||
{% endfor %}
|
||||
</div>
|
||||
{% endblock %}
|
||||
Reference in New Issue
Block a user