Diff -- /var/www/vhosts/3dshawn.com/ptmatrix.3dshawn.com/TEMPLATES/tf_calendar.html

O Operator
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
Restore this content →
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">&larr; $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 &rarr;</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()">&times;</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) + ' &middot; ' + 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,'&amp;').replace(/</g,'&lt;').replace(/>/g,'&gt;'); }
168})();
169</script>