Diff -- /var/www/vhosts/3dshawn.com/ptmatrix.3dshawn.com/TEMPLATES/tf_calendar.html
Diff
/var/www/vhosts/3dshawn.com/ptmatrix.3dshawn.com/TEMPLATES/tf_calendar.html
added on local at 2026-07-01 12:34:53
Added
+169
lines
Removed
-0
lines
Context
0
unchanged
Blobs
from
to 2e450e5ae026
to 2e450e5ae026
Unified diff
Naive LCS-based line diff. Additions in emerald, deletions in rose. Both sides decompressed live from BLOB_STORE.| 1 | <style> | |
| 2 | .cal-grid { display: grid; grid-template-columns: repeat(7, 1fr); gap: 0; background: transparent; border: 1px solid rgba(90,169,255,0.25); border-radius: var(--radius, 8px); overflow: hidden; } | |
| 3 | .cal-head { background: var(--col-bg-1); padding: 8px 10px; font-size: 11px; text-transform: uppercase; color: var(--col-text-muted, var(--col-text-dim)); font-weight: 600; letter-spacing: .05em; border-right: 1px solid rgba(90,169,255,0.25); border-bottom: 1px solid rgba(90,169,255,0.25); } | |
| 4 | .cal-head:nth-child(7) { border-right: none; } | |
| 5 | .cal-cell { background: linear-gradient(180deg, rgba(90,169,255,0.10) 0%, rgba(90,169,255,0.04) 100%); height: 130px; padding: 6px 8px; position: relative; font-size: 12px; overflow: hidden; cursor: pointer; transition: background 0.18s; border-right: 1px solid rgba(90,169,255,0.25); border-bottom: 1px solid rgba(90,169,255,0.25); } | |
| 6 | .cal-cell:nth-child(7n) { border-right: none; } | |
| 7 | .cal-cell:hover { background: linear-gradient(180deg, rgba(90,169,255,0.18) 0%, rgba(90,169,255,0.08) 100%); } | |
| 8 | .cal-cell.out { background: var(--col-bg-1); color: var(--col-text-dim); cursor: default; } | |
| 9 | .cal-cell.out:hover { background: var(--col-bg-1); } | |
| 10 | .cal-cell.today { background: var(--col-primary-soft, rgba(90,169,255,0.10)); } | |
| 11 | .cal-day-num { font-weight: 600; color: var(--col-text); font-size: 13px; } | |
| 12 | .cal-cell.out .cal-day-num { color: var(--col-text-dim); } | |
| 13 | .cal-cell.today .cal-day-num { color: var(--col-primary); } | |
| 14 | .cal-task-item { | |
| 15 | display: block; | |
| 16 | margin-top: 4px; | |
| 17 | padding: 3px 6px; | |
| 18 | border-radius: 4px; | |
| 19 | background: var(--col-bg-3, rgba(255,255,255,0.04)); | |
| 20 | color: var(--col-text); | |
| 21 | font-size: 11.5px; | |
| 22 | border-left: 3px solid var(--col-primary); | |
| 23 | white-space: nowrap; | |
| 24 | overflow: hidden; | |
| 25 | text-overflow: ellipsis; | |
| 26 | } | |
| 27 | .cal-more { | |
| 28 | display: block; | |
| 29 | margin-top: 4px; | |
| 30 | font-size: 11px; | |
| 31 | color: var(--col-primary); | |
| 32 | font-weight: 600; | |
| 33 | } | |
| 34 | /* Day-detail overlay */ | |
| 35 | .cal-overlay { | |
| 36 | display: none; | |
| 37 | position: fixed; | |
| 38 | inset: 0; | |
| 39 | background: rgba(0,0,0,0.65); | |
| 40 | z-index: 1000; | |
| 41 | align-items: flex-start; | |
| 42 | justify-content: center; | |
| 43 | padding-top: 60px; | |
| 44 | } | |
| 45 | .cal-overlay.open { display: flex; } | |
| 46 | .cal-overlay-card { | |
| 47 | background: var(--col-surface); | |
| 48 | border: 1px solid var(--col-border); | |
| 49 | border-radius: 12px; | |
| 50 | width: 100%; | |
| 51 | max-width: 600px; | |
| 52 | max-height: 80vh; | |
| 53 | overflow-y: auto; | |
| 54 | padding: 22px 24px; | |
| 55 | } | |
| 56 | .cal-overlay-head { display: flex; justify-content: space-between; align-items: flex-start; margin-bottom: 14px; } | |
| 57 | .cal-overlay-head h2 { margin: 0; font-size: 22px; } | |
| 58 | .cal-overlay-close { | |
| 59 | background: none; border: none; color: var(--col-text-dim); cursor: pointer; font-size: 22px; padding: 0; line-height: 1; | |
| 60 | } | |
| 61 | .cal-overlay-list { display: flex; flex-direction: column; gap: 8px; margin-bottom: 18px; } | |
| 62 | .cal-overlay-item { | |
| 63 | display: flex; gap: 10px; padding: 10px 12px; | |
| 64 | background: var(--col-bg-3, rgba(255,255,255,0.04)); | |
| 65 | border-left: 3px solid var(--col-primary); | |
| 66 | border-radius: 6px; | |
| 67 | text-decoration: none; | |
| 68 | color: var(--col-text); | |
| 69 | align-items: center; | |
| 70 | } | |
| 71 | .cal-overlay-item:hover { background: var(--col-surface-3, rgba(255,255,255,0.06)); } | |
| 72 | .cal-overlay-item .meta { font-size: 11px; color: var(--col-text-dim); } | |
| 73 | .cal-add-form { display: grid; grid-template-columns: 1fr 1fr auto; gap: 8px; padding-top: 14px; border-top: 1px solid var(--col-border); } | |
| 74 | .cal-add-form input, .cal-add-form select { padding: 8px 10px; border-radius: 6px; border: 1px solid var(--col-border); background: var(--col-surface-2, var(--col-bg-3)); color: var(--col-text); } | |
| 75 | .cal-add-form .full { grid-column: 1 / -1; } | |
| 76 | .cal-add-form button { padding: 8px 14px; } | |
| 77 | </style> | |
| 78 | <div class="page-header"> | |
| 79 | <div><h1>Calendar</h1><p class="subtitle">$month_label $y</p></div> | |
| 80 | <div class="flex-end"> | |
| 81 | <a class="btn btn-sm[if:$scope_me] btn-primary[/if][if:!$scope_me] btn-ghost[/if]" href="/calendar.cgi?y=$y&m=$m&scope=me">My tasks</a> | |
| 82 | [if:$has_team]<a class="btn btn-sm[if:$scope_team] btn-primary[/if][if:!$scope_team] btn-ghost[/if]" href="/calendar.cgi?y=$y&m=$m&scope=team">My team</a>[/if] | |
| 83 | [if:$has_department]<a class="btn btn-sm[if:$scope_dept] btn-primary[/if][if:!$scope_dept] btn-ghost[/if]" href="/calendar.cgi?y=$y&m=$m&scope=dept">My department</a>[/if] | |
| 84 | [if:$is_mgr]<a class="btn btn-sm[if:$scope_all] btn-primary[/if][if:!$scope_all] btn-ghost[/if]" href="/calendar.cgi?y=$y&m=$m&scope=all">Whole company</a>[/if] | |
| 85 | <a class="btn btn-ghost btn-sm" href="/calendar.cgi?y=$py&m=$pm">← $pm/$py</a> | |
| 86 | <a class="btn btn-ghost btn-sm" href="/calendar.cgi">Today</a> | |
| 87 | <a class="btn btn-ghost btn-sm" href="/calendar.cgi?y=$ny&m=$nm">$nm/$ny →</a> | |
| 88 | </div> | |
| 89 | </div> | |
| 90 | ||
| 91 | <div class="cal-grid"> | |
| 92 | <div class="cal-head">Sun</div><div class="cal-head">Mon</div><div class="cal-head">Tue</div><div class="cal-head">Wed</div><div class="cal-head">Thu</div><div class="cal-head">Fri</div><div class="cal-head">Sat</div> | |
| 93 | [loop:@cells] | |
| 94 | <div class="cal-cell[if:!$loop1.in_month] out[/if][if:$loop1.is_today] today[/if][if:$loop1.is_weekend] weekend[/if]" data-date="$loop1.d_str"> | |
| 95 | <div class="cal-day-num">$loop1.day_num</div> | |
| 96 | [if:$loop1.has_tasks] | |
| 97 | [loop:@loop1.tasks_top] | |
| 98 | <div class="cal-task-item" style="border-left-color:$loop2.project_color" title="$loop2.project_name">$loop2.title</div> | |
| 99 | [/loop] | |
| 100 | [if:$loop1.more_count]<a class="cal-more" href="#">+$loop1.more_count more</a>[/if] | |
| 101 | [/if] | |
| 102 | </div> | |
| 103 | [/loop] | |
| 104 | </div> | |
| 105 | ||
| 106 | <!-- Day-detail overlay --> | |
| 107 | <div class="cal-overlay" id="cal-overlay"> | |
| 108 | <div class="cal-overlay-card"> | |
| 109 | <div class="cal-overlay-head"> | |
| 110 | <h2 id="cal-overlay-date">-</h2> | |
| 111 | <button class="cal-overlay-close" onclick="closeCalOverlay()">×</button> | |
| 112 | </div> | |
| 113 | <div class="cal-overlay-list" id="cal-overlay-list"></div> | |
| 114 | <form class="cal-add-form" method="POST" action="/task_action.cgi"> | |
| 115 | <input type="hidden" name="act" value="create"> | |
| 116 | <input type="hidden" name="due_date" id="cal-add-due"> | |
| 117 | <input type="hidden" name="back" value="/calendar.cgi?y=$y&m=$m"> | |
| 118 | <select name="project_id" required> | |
| 119 | <option value="">Project...</option> | |
| 120 | [loop:@projects] | |
| 121 | <option value="$loop1.id">$loop1.name</option> | |
| 122 | [/loop] | |
| 123 | </select> | |
| 124 | <input class="full" type="text" name="title" placeholder="Task title..." required> | |
| 125 | <button type="submit" class="btn btn-primary">Add task</button> | |
| 126 | </form> | |
| 127 | </div> | |
| 128 | </div> | |
| 129 | ||
| 130 | <script> | |
| 131 | (function(){ | |
| 132 | var overlay = document.getElementById('cal-overlay'); | |
| 133 | var dateLabel = document.getElementById('cal-overlay-date'); | |
| 134 | var listEl = document.getElementById('cal-overlay-list'); | |
| 135 | var dueInput = document.getElementById('cal-add-due'); | |
| 136 | // Build day-data map from JSON | |
| 137 | var dayData = $cells_json; | |
| 138 | document.querySelectorAll('.cal-cell:not(.out)').forEach(function(cell){ | |
| 139 | cell.addEventListener('click', function(e){ | |
| 140 | if (e.target.closest('.cal-task-item') && !e.target.closest('.cal-more')) return; | |
| 141 | var d = cell.dataset.date; | |
| 142 | openCalOverlay(d); | |
| 143 | }); | |
| 144 | }); | |
| 145 | function openCalOverlay(dstr) { | |
| 146 | var data = dayData[dstr] || {tasks: []}; | |
| 147 | dateLabel.textContent = dstr; | |
| 148 | dueInput.value = dstr; | |
| 149 | listEl.innerHTML = ''; | |
| 150 | if (!data.tasks.length) { | |
| 151 | listEl.innerHTML = '<div style="color:var(--col-text-dim);font-size:13px;padding:10px 0">No tasks on this day.</div>'; | |
| 152 | } else { | |
| 153 | data.tasks.forEach(function(t){ | |
| 154 | var a = document.createElement('a'); | |
| 155 | a.className = 'cal-overlay-item'; | |
| 156 | a.href = '/task.cgi?id=' + t.id; | |
| 157 | a.style.borderLeftColor = t.project_color; | |
| 158 | a.innerHTML = '<div style="flex:1"><div style="font-weight:600">' + escapeHtml(t.title) + '</div><div class="meta">' + escapeHtml(t.project_name) + ' · ' + escapeHtml(t.priority || '') + '</div></div>'; | |
| 159 | listEl.appendChild(a); | |
| 160 | }); | |
| 161 | } | |
| 162 | overlay.classList.add('open'); | |
| 163 | } | |
| 164 | window.closeCalOverlay = function(){ overlay.classList.remove('open'); }; | |
| 165 | overlay.addEventListener('click', function(e){ if (e.target === overlay) closeCalOverlay(); }); | |
| 166 | document.addEventListener('keydown', function(e){ if (e.key === 'Escape') closeCalOverlay(); }); | |
| 167 | function escapeHtml(s) { return String(s||'').replace(/&/g,'&').replace(/</g,'<').replace(/>/g,'>'); } | |
| 168 | })(); | |
| 169 | </script> |