Links and Other Enhancements

This commit is contained in:
2026-03-02 19:55:04 +00:00
parent cf84d6d2dd
commit 0ed86ee2dc
24 changed files with 475 additions and 153 deletions

View File

@@ -87,9 +87,9 @@
<svg class="nav-icon" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><path d="M13 2H6a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V9z"/><polyline points="13 2 13 9 20 9"/></svg>
Files
</a>
<a href="/weblinks" class="nav-item {{ 'active' if active_nav == 'weblinks' }}">
<a href="/weblinks" class="nav-item {{ 'active' if active_nav == 'bookmarks' }}">
<svg class="nav-icon" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"/><polyline points="15 3 21 3 21 9"/><line x1="10" y1="14" x2="21" y2="3"/></svg>
Weblinks
Bookmarks
</a>
<a href="/time" class="nav-item {{ 'active' if active_nav == 'time' }}">
<svg class="nav-icon" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><circle cx="12" cy="12" r="10"/><polyline points="12 6 12 12 16 14"/></svg>
@@ -234,7 +234,7 @@
<a href="/decisions" class="mob-more__item"><span>Decisions</span></a>
<a href="/contacts" class="mob-more__item"><span>Contacts</span></a>
<a href="/processes" class="mob-more__item"><span>Processes</span></a>
<a href="/weblinks" class="mob-more__item"><span>Weblinks</span></a>
<a href="/weblinks" class="mob-more__item"><span>Bookmarks</span></a>
<a href="/admin" class="mob-more__item"><span>Admin</span></a>
</div>
</body>

View File

@@ -75,8 +75,8 @@
{% if item.converted_to_id %}
{% if item.converted_to_type == 'list_item' and item.list_id %}
<a href="/lists/{{ item.list_id }}" class="btn btn-ghost btn-xs">View &rarr;</a>
{% elif item.converted_to_type == 'weblink' %}
<a href="/weblinks" class="btn btn-ghost btn-xs">View &rarr;</a>
{% elif item.converted_to_type == 'link' %}
<a href="/links" class="btn btn-ghost btn-xs">View &rarr;</a>
{% elif item.converted_to_type in ('task', 'note', 'project', 'contact', 'decision') %}
<a href="/{{ item.converted_to_type }}s/{{ item.converted_to_id }}" class="btn btn-ghost btn-xs">View &rarr;</a>
{% endif %}

View File

@@ -132,7 +132,7 @@
<input type="text" name="title" class="form-input" value="{{ item.raw_text }}" required>
</div>
{% elif convert_type == 'weblink' %}
{% elif convert_type == 'link' %}
<div class="form-group full-width">
<label class="form-label">Label</label>
<input type="text" name="label" class="form-input" value="{{ prefill_label }}" required>

View File

@@ -91,4 +91,50 @@
{% endif %}
</div>
</div>
<!-- Project Deadlines -->
{% if overdue_projects or upcoming_projects %}
<div class="card mt-4">
<div class="card-header">
<h2 class="card-title">Project Deadlines</h2>
<a href="/projects/" class="btn btn-ghost btn-sm">All Projects</a>
</div>
{% if overdue_projects %}
<div class="text-xs text-muted mb-2" style="font-weight:600; color: var(--red);">OVERDUE</div>
{% for p in overdue_projects %}
<div class="list-row">
<span class="priority-dot priority-{{ p.priority }}"></span>
<span class="row-title"><a href="/projects/{{ p.id }}">{{ p.name }}</a></span>
{% if p.domain_name %}
<span class="row-meta">{{ p.domain_name }}</span>
{% endif %}
<div class="project-progress-mini">
<div class="project-progress-bar" style="width: {{ ((p.done_count / p.task_count * 100) if p.task_count else 0)|int }}%"></div>
</div>
<span class="row-meta" style="min-width: 32px; text-align: right; font-size: 0.72rem;">{{ p.done_count }}/{{ p.task_count }}</span>
<span class="row-meta overdue">{{ p.target_date }}</span>
</div>
{% endfor %}
{% endif %}
{% if upcoming_projects %}
<div class="text-xs text-muted mb-2 {{ 'mt-3' if overdue_projects }}" style="font-weight:600;">NEXT 30 DAYS</div>
{% for p in upcoming_projects %}
<div class="list-row">
<span class="priority-dot priority-{{ p.priority }}"></span>
<span class="row-title"><a href="/projects/{{ p.id }}">{{ p.name }}</a></span>
{% if p.domain_name %}
<span class="row-meta">{{ p.domain_name }}</span>
{% endif %}
<div class="project-progress-mini">
<div class="project-progress-bar" style="width: {{ ((p.done_count / p.task_count * 100) if p.task_count else 0)|int }}%"></div>
</div>
<span class="row-meta" style="min-width: 32px; text-align: right; font-size: 0.72rem;">{{ p.done_count }}/{{ p.task_count }}</span>
<span class="row-meta">{{ p.target_date }}</span>
</div>
{% endfor %}
{% endif %}
</div>
{% endif %}
{% endblock %}

View File

@@ -7,11 +7,14 @@
<div class="form-grid">
<div class="form-group"><label class="form-label">Label *</label><input type="text" name="label" class="form-input" required value="{{ item.label if item else '' }}"></div>
<div class="form-group"><label class="form-label">URL *</label><input type="url" name="url" class="form-input" required value="{{ item.url if item else '' }}"></div>
<div class="form-group"><label class="form-label">Domain *</label>
<select name="domain_id" class="form-select" required>{% for d in domains %}<option value="{{ d.id }}" {{ 'selected' if (item and item.domain_id|string == d.id|string) or (not item and prefill_domain_id == d.id|string) }}>{{ d.name }}</option>{% endfor %}</select></div>
<div class="form-group"><label class="form-label">Domain</label>
<select name="domain_id" class="form-select"><option value="">-- None --</option>{% for d in domains %}<option value="{{ d.id }}" {{ 'selected' if (item and item.domain_id and item.domain_id|string == d.id|string) or (not item and prefill_domain_id == d.id|string) }}>{{ d.name }}</option>{% endfor %}</select></div>
<div class="form-group"><label class="form-label">Project</label>
<select name="project_id" class="form-select"><option value="">-- None --</option>{% for p in projects %}<option value="{{ p.id }}" {{ 'selected' if (item and item.project_id and item.project_id|string == p.id|string) or (not item and prefill_project_id == p.id|string) }}>{{ p.name }}</option>{% endfor %}</select></div>
<div class="form-group full-width"><label class="form-label">Tags</label><input type="text" name="tags" class="form-input" placeholder="tag1, tag2, ..." value="{{ item.tags|join(', ') if item and item.tags else '' }}"></div>
<div class="form-group full-width"><label class="form-label">Description</label><textarea name="description" class="form-textarea" rows="3">{{ item.description if item and item.description else '' }}</textarea></div>
{% if prefill_task_id is defined and prefill_task_id %}<input type="hidden" name="task_id" value="{{ prefill_task_id }}">{% endif %}
{% if prefill_meeting_id is defined and prefill_meeting_id %}<input type="hidden" name="meeting_id" value="{{ prefill_meeting_id }}">{% endif %}
<div class="form-actions"><button type="submit" class="btn btn-primary">{{ 'Save' if item else 'Create' }}</button><a href="/links" class="btn btn-secondary">Cancel</a></div>
</div>
</form></div>

View File

@@ -23,6 +23,11 @@
{% if item.start_at and item.end_at %}
<span class="detail-meta-item">{{ item.start_at.strftime('%H:%M') }} - {{ item.end_at.strftime('%H:%M') }}</span>
{% endif %}
{% if projects %}
{% for p in projects %}
<span class="detail-meta-item"><a href="/projects/{{ p.id }}" style="color: {{ p.domain_color or 'var(--accent)' }};">{{ p.name }}</a></span>
{% endfor %}
{% endif %}
{% if item.tags %}
<div class="mt-1">{% for tag in item.tags %}<span class="row-tag">{{ tag }}</span>{% endfor %}</div>
{% endif %}
@@ -32,9 +37,10 @@
<div class="tab-strip">
<a href="/meetings/{{ item.id }}?tab=overview" class="tab-item {{ 'active' if tab == 'overview' }}">Overview</a>
<a href="/meetings/{{ item.id }}?tab=notes" class="tab-item {{ 'active' if tab == 'notes' }}">Notes{% if counts.notes %} ({{ counts.notes }}){% endif %}</a>
<a href="/meetings/{{ item.id }}?tab=weblinks" class="tab-item {{ 'active' if tab == 'weblinks' }}">Weblinks{% if counts.weblinks %} ({{ counts.weblinks }}){% endif %}</a>
<a href="/meetings/{{ item.id }}?tab=links" class="tab-item {{ 'active' if tab == 'links' }}">Links{% if counts.links %} ({{ counts.links }}){% endif %}</a>
<a href="/meetings/{{ item.id }}?tab=files" class="tab-item {{ 'active' if tab == 'files' }}">Files{% if counts.files %} ({{ counts.files }}){% endif %}</a>
<a href="/meetings/{{ item.id }}?tab=lists" class="tab-item {{ 'active' if tab == 'lists' }}">Lists{% if counts.lists %} ({{ counts.lists }}){% endif %}</a>
<a href="/meetings/{{ item.id }}?tab=decisions" class="tab-item {{ 'active' if tab == 'decisions' }}">Decisions{% if counts.decisions %} ({{ counts.decisions }}){% endif %}</a>
<a href="/meetings/{{ item.id }}?tab=processes" class="tab-item {{ 'active' if tab == 'processes' }}">Processes</a>
<a href="/meetings/{{ item.id }}?tab=contacts" class="tab-item {{ 'active' if tab == 'contacts' }}">Contacts{% if counts.contacts %} ({{ counts.contacts }}){% endif %}</a>
</div>
@@ -122,15 +128,15 @@
<div class="empty-state"><div class="empty-state-text">No notes linked to this meeting</div></div>
{% endfor %}
{% elif tab == 'weblinks' %}
<a href="/weblinks/create?meeting_id={{ item.id }}" class="btn btn-ghost btn-sm mb-3">+ New Weblink</a>
{% elif tab == 'links' %}
<a href="/links/create?meeting_id={{ item.id }}" class="btn btn-ghost btn-sm mb-3">+ New Link</a>
{% for w in tab_data %}
<div class="list-row">
<span class="row-title"><a href="{{ w.url }}" target="_blank">{{ w.label }}</a></span>
<span class="row-meta">{{ w.url[:50] }}{% if w.url|length > 50 %}...{% endif %}</span>
</div>
{% else %}
<div class="empty-state"><div class="empty-state-text">No weblinks linked to this meeting</div></div>
<div class="empty-state"><div class="empty-state-text">No links linked to this meeting</div></div>
{% endfor %}
{% elif tab == 'files' %}
@@ -155,6 +161,38 @@
<div class="empty-state"><div class="empty-state-text">No lists linked to this meeting</div></div>
{% endfor %}
{% elif tab == 'decisions' %}
<div class="card mb-4">
<form action="/meetings/{{ item.id }}/decisions/add" method="post" class="flex gap-2 items-end" style="padding: 12px;">
<div class="form-group" style="flex:1; margin:0;">
<label class="form-label">Decision</label>
<select name="decision_id" class="form-select" required>
<option value="">Select decision...</option>
{% for d in all_decisions %}
<option value="{{ d.id }}">{{ d.title }}</option>
{% endfor %}
</select>
</div>
<button type="submit" class="btn btn-primary btn-sm">Link</button>
</form>
</div>
<a href="/decisions/create?meeting_id={{ item.id }}" class="btn btn-ghost btn-sm mb-3">+ New Decision</a>
{% for d in tab_data %}
<div class="list-row">
<span class="row-title"><a href="/decisions/{{ d.id }}">{{ d.title }}</a></span>
<span class="status-badge status-{{ d.status }}">{{ d.status }}</span>
{% if d.impact %}<span class="row-tag">{{ d.impact }}</span>{% endif %}
{% if d.decided_at %}<span class="row-meta">{{ d.decided_at.strftime('%Y-%m-%d') if d.decided_at else '' }}</span>{% endif %}
<div class="row-actions">
<form action="/meetings/{{ item.id }}/decisions/{{ d.id }}/remove" method="post" style="display:inline">
<button class="btn btn-ghost btn-xs" title="Unlink">Unlink</button>
</form>
</div>
</div>
{% else %}
<div class="empty-state"><div class="empty-state-text">No decisions linked to this meeting</div></div>
{% endfor %}
{% elif tab == 'processes' %}
<div class="empty-state"><div class="empty-state-text">Process management coming soon</div></div>

View File

@@ -39,6 +39,7 @@
<a href="/projects/{{ item.id }}?tab=files" class="tab-item {{ 'active' if tab == 'files' }}">Files{% if counts.files %} ({{ counts.files }}){% endif %}</a>
<a href="/projects/{{ item.id }}?tab=lists" class="tab-item {{ 'active' if tab == 'lists' }}">Lists{% if counts.lists %} ({{ counts.lists }}){% endif %}</a>
<a href="/projects/{{ item.id }}?tab=decisions" class="tab-item {{ 'active' if tab == 'decisions' }}">Decisions{% if counts.decisions %} ({{ counts.decisions }}){% endif %}</a>
<a href="/projects/{{ item.id }}?tab=meetings" class="tab-item {{ 'active' if tab == 'meetings' }}">Meetings{% if counts.meetings %} ({{ counts.meetings }}){% endif %}</a>
<a href="/projects/{{ item.id }}?tab=processes" class="tab-item {{ 'active' if tab == 'processes' }}">Processes</a>
<a href="/projects/{{ item.id }}?tab=contacts" class="tab-item {{ 'active' if tab == 'contacts' }}">Contacts{% if counts.contacts %} ({{ counts.contacts }}){% endif %}</a>
</div>
@@ -130,6 +131,37 @@
<div class="empty-state"><div class="empty-state-text">No decisions linked to this project</div></div>
{% endfor %}
{% elif tab == 'meetings' %}
<a href="/meetings/create" class="btn btn-ghost btn-sm mb-3">+ New Meeting</a>
<div class="card mb-4">
<form action="/projects/{{ item.id }}/meetings/add" method="post" class="flex gap-2 items-end" style="padding: 12px;">
<div class="form-group" style="flex:1; margin:0;">
<label class="form-label">Meeting</label>
<select name="meeting_id" class="form-select" required>
<option value="">Select meeting...</option>
{% for m in all_meetings %}
<option value="{{ m.id }}">{{ m.title }} ({{ m.meeting_date }})</option>
{% endfor %}
</select>
</div>
<button type="submit" class="btn btn-primary btn-sm">Add</button>
</form>
</div>
{% for m in tab_data %}
<div class="list-row">
<span class="row-title"><a href="/meetings/{{ m.id }}">{{ m.title }}</a></span>
<span class="row-meta">{{ m.meeting_date }}</span>
<span class="status-badge status-{{ m.status }}">{{ m.status }}</span>
<div class="row-actions">
<form action="/projects/{{ item.id }}/meetings/{{ m.id }}/remove" method="post" style="display:inline">
<button class="btn btn-ghost btn-xs" title="Remove">Remove</button>
</form>
</div>
</div>
{% else %}
<div class="empty-state"><div class="empty-state-text">No meetings linked to this project</div></div>
{% endfor %}
{% elif tab == 'processes' %}
<div class="empty-state"><div class="empty-state-text">Process management coming soon</div></div>

View File

@@ -58,7 +58,7 @@
<div class="tab-strip">
<a href="/tasks/{{ item.id }}?tab=overview" class="tab-item {{ 'active' if tab == 'overview' }}">Overview{% if counts.overview %} ({{ counts.overview }}){% endif %}</a>
<a href="/tasks/{{ item.id }}?tab=notes" class="tab-item {{ 'active' if tab == 'notes' }}">Notes{% if counts.notes %} ({{ counts.notes }}){% endif %}</a>
<a href="/tasks/{{ item.id }}?tab=weblinks" class="tab-item {{ 'active' if tab == 'weblinks' }}">Weblinks{% if counts.weblinks %} ({{ counts.weblinks }}){% endif %}</a>
<a href="/tasks/{{ item.id }}?tab=links" class="tab-item {{ 'active' if tab == 'links' }}">Links{% if counts.links %} ({{ counts.links }}){% endif %}</a>
<a href="/tasks/{{ item.id }}?tab=files" class="tab-item {{ 'active' if tab == 'files' }}">Files{% if counts.files %} ({{ counts.files }}){% endif %}</a>
<a href="/tasks/{{ item.id }}?tab=lists" class="tab-item {{ 'active' if tab == 'lists' }}">Lists{% if counts.lists %} ({{ counts.lists }}){% endif %}</a>
<a href="/tasks/{{ item.id }}?tab=decisions" class="tab-item {{ 'active' if tab == 'decisions' }}">Decisions{% if counts.decisions %} ({{ counts.decisions }}){% endif %}</a>
@@ -107,15 +107,15 @@
<div class="empty-state"><div class="empty-state-text">No notes linked to this task</div></div>
{% endfor %}
{% elif tab == 'weblinks' %}
<a href="/weblinks/create?task_id={{ item.id }}" class="btn btn-ghost btn-sm mb-3">+ New Weblink</a>
{% elif tab == 'links' %}
<a href="/links/create?task_id={{ item.id }}" class="btn btn-ghost btn-sm mb-3">+ New Link</a>
{% for w in tab_data %}
<div class="list-row">
<span class="row-title"><a href="{{ w.url }}" target="_blank">{{ w.label }}</a></span>
<span class="row-meta">{{ w.url[:50] }}{% if w.url|length > 50 %}...{% endif %}</span>
</div>
{% else %}
<div class="empty-state"><div class="empty-state-text">No weblinks linked to this task</div></div>
<div class="empty-state"><div class="empty-state-text">No links linked to this task</div></div>
{% endfor %}
{% elif tab == 'files' %}

View File

@@ -44,8 +44,8 @@
{% if prefill_task_id is defined and prefill_task_id %}<input type="hidden" name="task_id" value="{{ prefill_task_id }}">{% endif %}
{% if prefill_meeting_id is defined and prefill_meeting_id %}<input type="hidden" name="meeting_id" value="{{ prefill_meeting_id }}">{% endif %}
<div class="form-actions">
<button type="submit" class="btn btn-primary">{{ 'Save Changes' if item else 'Add Weblink' }}</button>
<a href="{{ '/tasks/' ~ prefill_task_id ~ '?tab=weblinks' if prefill_task_id is defined and prefill_task_id else '/weblinks' }}" class="btn btn-secondary">Cancel</a>
<button type="submit" class="btn btn-primary">{{ 'Save Changes' if item else 'Add Link' }}</button>
<a href="{{ '/tasks/' ~ prefill_task_id ~ '?tab=links' if prefill_task_id is defined and prefill_task_id else '/weblinks' }}" class="btn btn-secondary">Cancel</a>
</div>
</form>
</div>

View File

@@ -1,10 +1,10 @@
{% extends "base.html" %}
{% block content %}
<div class="page-header">
<h1 class="page-title">Weblinks<span class="page-count">{{ items|length }}</span></h1>
<h1 class="page-title">Bookmarks<span class="page-count">{{ items|length }}</span></h1>
<div class="flex gap-2">
<a href="/weblinks/folders/create" class="btn btn-secondary">+ New Folder</a>
<a href="/weblinks/create{{ '?folder_id=' ~ current_folder_id if current_folder_id }}" class="btn btn-primary">+ New Weblink</a>
<a href="/weblinks/create{{ '?folder_id=' ~ current_folder_id if current_folder_id }}" class="btn btn-primary">+ New Link</a>
</div>
</div>
@@ -12,7 +12,7 @@
<!-- Folder sidebar -->
<div class="weblinks-folders">
<a href="/weblinks" class="weblink-folder-item {{ 'active' if not current_folder_id }}">
All Weblinks
All Links
</a>
{% for folder in top_folders %}
<a href="/weblinks?folder_id={{ folder.id }}" class="weblink-folder-item {{ 'active' if current_folder_id == folder.id|string }}">
@@ -28,7 +28,7 @@
{% endfor %}
</div>
<!-- Weblinks list -->
<!-- Links list -->
<div class="weblinks-content">
{% if current_folder %}
<div class="flex items-center justify-between mb-2">
@@ -57,7 +57,7 @@
{% endif %}
<div class="row-actions">
<a href="/weblinks/{{ item.id }}/edit" class="btn btn-ghost btn-xs">Edit</a>
<form action="/weblinks/{{ item.id }}/delete" method="post" data-confirm="Delete this weblink?" style="display:inline">
<form action="/weblinks/{{ item.id }}/delete" method="post" data-confirm="Delete this link?" style="display:inline">
<button type="submit" class="btn btn-ghost btn-xs" style="color: var(--red)">Del</button>
</form>
</div>
@@ -67,8 +67,8 @@
{% else %}
<div class="empty-state">
<div class="empty-state-icon">&#128279;</div>
<div class="empty-state-text">No weblinks{{ ' in this folder' if current_folder }} yet</div>
<a href="/weblinks/create{{ '?folder_id=' ~ current_folder_id if current_folder_id }}" class="btn btn-primary">Add Weblink</a>
<div class="empty-state-text">No links{{ ' in this folder' if current_folder }} yet</div>
<a href="/weblinks/create{{ '?folder_id=' ~ current_folder_id if current_folder_id }}" class="btn btn-primary">Add Link</a>
</div>
{% endif %}
</div>