create-pmos 0.129.0 → 0.131.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/package.json +1 -1
- package/payload/KIT-VERSION +1 -1
- package/payload/planning/evals/eval-calibration.md +1 -1
- package/payload/planning/okrs/health-budgets.md +1 -1
- package/payload/state/discoveries.md +1 -1
- package/workspace/c3-one-home-test.js +8 -3
- package/workspace/c3-work-test.js +200 -0
- package/workspace/fixtures/one-home-baseline.json +0 -91
- package/workspace/guide/briefing.md +60 -0
- package/workspace/guide/calendar-popup.md +46 -0
- package/workspace/guide/console-calendar.md +65 -0
- package/workspace/guide/index.md +4 -0
- package/workspace/guide/layout.md +1 -0
- package/workspace/guide/my-work.md +76 -1
- package/workspace/lib/calendar-layers.js +372 -0
- package/workspace/lib/pm-items.js +71 -6
- package/workspace/lib/report-needs.js +1 -1
- package/workspace/lib/route-modules.js +1 -0
- package/workspace/lib/routes-brief-page.js +187 -0
- package/workspace/lib/routes-calendar-views.js +112 -3
- package/workspace/lib/routes-pm-items.js +123 -13
- package/workspace/lib/work-focus.js +106 -0
- package/workspace/package-lock.json +2 -2
- package/workspace/package.json +1 -1
- package/workspace/public/pm/c3-brief-data.js +11 -0
- package/workspace/public/pm/c3-brief-needs.js +145 -0
- package/workspace/public/pm/c3-brief-pulse.js +70 -0
- package/workspace/public/pm/c3-brief-today.js +44 -0
- package/workspace/public/pm/c3-calendar.js +392 -0
- package/workspace/public/pm/c3-calpop.js +103 -0
- package/workspace/public/pm/c3-demo-brief-page.js +54 -0
- package/workspace/public/pm/c3-demo-cal4.js +114 -0
- package/workspace/public/pm/c3-demo-data.js +79 -77
- package/workspace/public/pm/c3-demo-misc2.js +4 -16
- package/workspace/public/pm/c3-demo-work-ix.js +19 -67
- package/workspace/public/pm/c3-demo.js +11 -4
- package/workspace/public/pm/c3-shell.js +27 -149
- package/workspace/public/pm/calendar-views.js +11 -3
- package/workspace/public/pm/components.css +1 -0
- package/workspace/public/pm/console3.css +198 -0
- package/workspace/public/pm/pm-work-view.js +364 -172
- package/workspace/public/pm/work-place.js +58 -0
- package/workspace/test-files.json +7 -1
- package/workspace/test-lists/calendar-layers.json +5 -0
- package/workspace/test-lists/calendar-time-page.json +5 -0
- package/workspace/test-lists/calpop.json +4 -0
- package/workspace/test-lists/console3-work-page.json +9 -0
- package/workspace/public/pm/c3-demo-work2.js +0 -13
|
@@ -1,8 +1,7 @@
|
|
|
1
1
|
/* pm/c3-shell.js — the console3 SHELL as its own page (/c3.html). The mockup (console3.html) is the UI: the header (title and date,
|
|
2
2
|
* the icon buttons, the bell), the tab bar (Briefing, Calendar, Work, Initiatives, Reports) and the three-column Briefing. This
|
|
3
3
|
* file draws only the frame and composes the real views into it, each through its own mount function:
|
|
4
|
-
* Briefing
|
|
5
|
-
* middle mountCalendarViews (day) + a portfolio pulse drawn from the Calendar's own gantt rows
|
|
4
|
+
* Briefing one column, the brief: the deck (mountBriefing), Today (c3-brief-today.js), Needs you (c3-brief-needs.js), Portfolio pulse (c3-brief-pulse.js)
|
|
6
5
|
* right the dock (c3-dock.js): the repository, branch and session tree, the selected session's detail, "Open the session" to /
|
|
7
6
|
* Every tab but Briefing also carries the mockup's "Plan: Decide what gates the day" lens row and deck (c3-plan.js planNode).
|
|
8
7
|
* Calendar mountCalendarViews Work mountPmWork
|
|
@@ -17,6 +16,10 @@ import { pmGet } from './http.js';
|
|
|
17
16
|
import { ensureC3Css, c3ic, c3Phone, mountPmWork } from './pm-work-view.js';
|
|
18
17
|
import { mountBriefing, showCard, flipBack } from './briefing-deck.js';
|
|
19
18
|
import { mountCalendarViews } from './calendar-views.js';
|
|
19
|
+
import { todaySection } from './c3-brief-today.js';
|
|
20
|
+
import { needsSection } from './c3-brief-needs.js';
|
|
21
|
+
import { pulse } from './c3-brief-pulse.js';
|
|
22
|
+
import { loadBriefPage } from './c3-brief-data.js';
|
|
20
23
|
import { mountLifecycle } from './lifecycle-lens.js';
|
|
21
24
|
import { mountForecast } from './timeline-forecast-view.js';
|
|
22
25
|
import { mountReleases } from './releases-view.js';
|
|
@@ -24,11 +27,11 @@ import { mountReportFamilies } from './report-families-view.js';
|
|
|
24
27
|
import { mountReports } from './c3-reports.js';
|
|
25
28
|
import { mountOutbox } from './outbox-panel.js';
|
|
26
29
|
import { createDock } from './c3-dock.js';
|
|
27
|
-
import {
|
|
28
|
-
import { makeXp, attachExpand } from './c3-expand.js';
|
|
30
|
+
import { reviewSection, handledRow, trustCard, footLine, rowApi, BX, toast, setNeedsTitle, hooks as briefHooks } from './c3-brief.js';
|
|
29
31
|
import { stopCard } from './c3-misc-panels.js';
|
|
30
32
|
import { openSheet } from './c3-sheet.js';
|
|
31
|
-
import {
|
|
33
|
+
import { mountCalPopupTrigger } from './c3-calpop.js';
|
|
34
|
+
import { planNode, setPlanScope, dueCard, crossLinks, newInitLine, portfolioCard } from './c3-plan.js';
|
|
32
35
|
import { initiativesViewCtx } from './registry.js';
|
|
33
36
|
import { mount as mountRoadmap } from './c3-roadmap.js';
|
|
34
37
|
import { mount as mountBreakdown } from './c3-breakdown.js';
|
|
@@ -40,7 +43,7 @@ import { mountDaypart } from './c3-daypart.js';
|
|
|
40
43
|
import { mountTicker } from './shell-ticker.js';
|
|
41
44
|
import { mountBell, openBellList } from './shell-bell.js';
|
|
42
45
|
import { onBriefing, loadBriefing } from './shell-ticker.js';
|
|
43
|
-
import {
|
|
46
|
+
import { registry, filterPalette, rowStep } from './briefing-model.js';
|
|
44
47
|
|
|
45
48
|
/* In demo mode each tab's deck asks for its own cards (the mockup draws a different deck per tab); real mode sends no scope. */
|
|
46
49
|
const sc = (name) => (DEMO ? name : undefined);
|
|
@@ -99,6 +102,7 @@ function header() {
|
|
|
99
102
|
S.bellHost = el('span', { class: 'c3pg-bell' });
|
|
100
103
|
S.tools.append(S.bellHost);
|
|
101
104
|
S.tools.append(ibtn('Search (Ctrl K)', 'search', { 'data-c3pg': 'search', 'aria-haspopup': 'dialog', onclick: () => openPalette() }));
|
|
105
|
+
mountCalPopupTrigger(S.tools); // the calendar button (before Search) and the key C (c3-calpop.js)
|
|
102
106
|
S.moreBtn = ibtn('More', 'more', { 'aria-haspopup': 'menu', 'aria-expanded': 'false', 'data-c3pg': 'more', onclick: toggleMore });
|
|
103
107
|
S.tools.append(el('span', { class: 'c3pg-menuwrap' }, S.moreBtn));
|
|
104
108
|
return el('div', { class: 'c3top' }, el('div', null, S.ttl, S.sub), S.tools);
|
|
@@ -240,130 +244,12 @@ function moveInd() {
|
|
|
240
244
|
S.ind.style.width = b.offsetWidth + 'px'; S.ind.style.transform = 'translateX(' + b.offsetLeft + 'px)';
|
|
241
245
|
}
|
|
242
246
|
|
|
243
|
-
/* ── the Briefing tab:
|
|
244
|
-
|
|
245
|
-
*
|
|
246
|
-
* only the needs with a hard deadline stay. */
|
|
247
|
-
function needsList() {
|
|
248
|
-
const count = el('span', { class: 'bdg g' }, '0');
|
|
249
|
-
const quick = el('span', { class: 'chips2 dim mono', style: 'font-size:var(--fs-2)' });
|
|
250
|
-
const list = el('ul', { class: 'list', role: 'list' });
|
|
251
|
-
const extra = el('div');
|
|
252
|
-
const alertHost = el('div');
|
|
253
|
-
const box = el('section', { class: 'card sect', 'data-c3pg': 'needs', 'aria-label': 'Needs you' },
|
|
254
|
-
el('div', { class: 'sh2' }, el('h2', null, c3ic('inbox', 'sm'), 'Needs you ', count)), alertHost, list, extra);
|
|
255
|
-
let sig = ''; let last = null;
|
|
256
|
-
const recount = () => {
|
|
257
|
-
const n = box.querySelectorAll('.nrow[data-needs-row]').length;
|
|
258
|
-
count.textContent = String(n);
|
|
259
|
-
if (!n && !list.querySelector('.fold')) list.replaceChildren(el('li', { class: 'fold' }, c3ic('check', 'sm'), 'Nothing needs you.'));
|
|
260
|
-
};
|
|
261
|
-
const ctx = { changed: recount };
|
|
262
|
-
const fill = (b) => {
|
|
263
|
-
last = b;
|
|
264
|
-
const inc = !!S.incident;
|
|
265
|
-
const needs = b && Array.isArray(b.needs) && b.needs.length ? b.needs.filter((n) => !BX.gone[n.key] && (!inc || n.hard)) : null;
|
|
266
|
-
const own = !needs && b && Array.isArray(b.own_needs) ? b.own_needs.filter((n) => n && !BX.gone[n.key]) : []; // the PM's own overdue and due-today items: overdue first, above the engine's cards
|
|
267
|
-
const key = needs ? needs.map((n) => n.key + n.headline) : own.map((n) => n.key + n.headline).concat(((b && b.cards) || []).map((c) => (c.key || '') + c.headline));
|
|
268
|
-
if (needs && S.pinNeed) { const at = needs.findIndex((n) => n.key === S.pinNeed); if (at > 0) needs.unshift(...needs.splice(at, 1)); } // a need the banner or the bell named rides to the top of the list: shown, not folded
|
|
269
|
-
const g = JSON.stringify([key, inc, !!(b && b.kept_out), S.pinNeed || '']);
|
|
270
|
-
if (g === sig) return; sig = g;
|
|
271
|
-
alertHost.replaceChildren(...(inc ? [el('div', { class: 'incident', role: 'status', 'data-c3pg': 'incident' }, c3ic('alert', 'lg'), el('div', null, el('b', null, 'Card payments failing since 07:40'), el('div', { class: 'dim', style: 'font-size:var(--fs-3)' }, '12% of checkouts. Sam on call. Only deadlines shown.')))] : []));
|
|
272
|
-
if (needs) {
|
|
273
|
-
if (!quick.isConnected) box.querySelector('.sh2').append(quick);
|
|
274
|
-
quick.textContent = ''; quick.append(c3ic('bolt', 'sm'), needs.filter((n) => n.quick).length + ' under 2 min');
|
|
275
|
-
list.replaceChildren(...needs.slice(0, 5).map((n, i) => needRow(n, i, ctx))); // the mockup shows five and folds the rest "below the line"
|
|
276
|
-
extra.replaceChildren(...(inc ? [] : belowLine(needs.slice(5), (n, i) => needRow(n, i + 5, ctx), b.kept_out)));
|
|
277
|
-
recount();
|
|
278
|
-
return;
|
|
279
|
-
}
|
|
280
|
-
const cards = ((b && b.cards) || []).map(cardView);
|
|
281
|
-
quick.remove();
|
|
282
|
-
const ownRows = (inc ? own.filter((n) => n.overdue) : own).map((n, i) => needRow(n, i, ctx));
|
|
283
|
-
const cardRows = cards.map((v, i) => {
|
|
284
|
-
const T = TAG_STYLE[v.tag] || TAG_STYLE['Just in'];
|
|
285
|
-
return needRow({ key: v.key || String(i), headline: v.headline, kind: v.tag, icon: T.icon, color: T.color, time: v.deadline && v.deadline.text ? v.deadline.text : null, src: v.tag, view: v }, i + ownRows.length, ctx);
|
|
286
|
-
});
|
|
287
|
-
const all = ownRows.concat(cardRows);
|
|
288
|
-
list.replaceChildren(...(all.length ? all : [el('li', { class: 'fold' }, c3ic('check', 'sm'), 'Nothing needs you.')]));
|
|
289
|
-
extra.replaceChildren();
|
|
290
|
-
count.textContent = String(all.length);
|
|
291
|
-
};
|
|
292
|
-
S.refreshNeeds = () => { sig = ''; if (last) fill(last); };
|
|
293
|
-
S.needsFill = fill;
|
|
294
|
-
onBriefing((b) => { S.brief = b; fill(b); });
|
|
295
|
-
loadBriefing();
|
|
296
|
-
return box;
|
|
297
|
-
}
|
|
298
|
-
|
|
299
|
-
/* portfolio pulse: the Calendar's own gantt rows (GET /api/calendar-views, quarter) as one status bar and a row per initiative */
|
|
300
|
-
const PST = { 'on time': ['ok', 'On time', 'var(--success)'], 'at risk': ['warn', 'At risk', 'var(--warning)'], delayed: ['bad', 'Delayed', 'var(--destructive)'], overdue: ['bad', 'Overdue', 'var(--destructive)'], 'no plan': ['', 'No plan', 'var(--muted-foreground)'] };
|
|
301
|
-
const PST_CLS = { 'on time': 'pst-ok', 'at risk': 'pst-warn', delayed: 'pst-bad', overdue: 'pst-bad', 'no plan': 'pst-none' };
|
|
302
|
-
|
|
303
|
-
/* A pulse row opens in place, like a Needs you row: the same c3-expand panel and the same case component. It never changes the tab. "Open initiative" inside the case is the only way out. */
|
|
304
|
-
const PULSE_OPEN = new Set();
|
|
305
|
-
function pulseCase(g) {
|
|
306
|
-
const f = (g.forecast && (g.forecast.end || g.forecast.start)) || null; const p = g.promised || null;
|
|
307
|
-
const ev = [];
|
|
308
|
-
if (p) ev.push(['clock', 'Promised ' + p, '', 'ok']);
|
|
309
|
-
if (f) ev.push(['clock', 'Forecast ' + f, '', g.slip_days > 0 ? 'warn' : 'ok']);
|
|
310
|
-
if (g.slip_days > 0) ev.push(['alert', 'Slips ' + g.slip_days + ' d past the promise.', '', 'warn']);
|
|
311
|
-
const why = (g.pulse && g.pulse.why) || (p ? 'Forecast ' + (f || 'not set') + ' vs promised ' + p + '.' : 'No promised date' + (f ? '; forecast ' + f : '') + '.');
|
|
312
|
-
return caseFile({ id: 'pulse:' + g.id, sit: why, chg: ev, go: ['goinit', g.id, 'Open initiative'] });
|
|
313
|
-
}
|
|
314
|
-
function inlineRows(list, rows, watch) {
|
|
315
|
-
const byId = new Map(rows.map((g) => [String(g.id), g]));
|
|
316
|
-
const enhance = () => list.querySelectorAll('[data-c3pg-prow]').forEach((btn) => {
|
|
317
|
-
if (btn.hasAttribute('data-expand')) return;
|
|
318
|
-
const g = byId.get(btn.getAttribute('data-c3pg-prow')); if (!g) return;
|
|
319
|
-
const id = String(g.id); const xp = makeXp(); let built = false;
|
|
320
|
-
(btn.closest('.prow') || btn).after(xp); btn.setAttribute('data-a', 'pulsexp'); btn.setAttribute('aria-label', 'Show details: ' + (g.title || g.id));
|
|
321
|
-
attachExpand(btn, xp, { key: 'pulse-' + id, initial: PULSE_OPEN.has(id), onToggle: (on) => {
|
|
322
|
-
if (on) { PULSE_OPEN.add(id); if (!built) { built = true; xp.firstChild.append(pulseCase(g)); } } else PULSE_OPEN.delete(id);
|
|
323
|
-
} });
|
|
324
|
-
});
|
|
325
|
-
enhance();
|
|
326
|
-
if (watch) new MutationObserver(enhance).observe(list, { childList: true });
|
|
327
|
-
}
|
|
328
|
-
|
|
329
|
-
function pulse() {
|
|
330
|
-
const body = el('div', null, el('p', { class: 'dim mono', style: 'font-size:var(--fs-2)' }, 'Reading the initiatives.'));
|
|
331
|
-
const box = el('section', { class: 'card', 'data-c3pg': 'pulse', style: 'gap:8px' },
|
|
332
|
-
el('div', { class: 'chips2', style: 'justify-content:space-between' },
|
|
333
|
-
el('h3', null, c3ic('init', 'sm'), 'Portfolio pulse'), el('span', { class: 'mono dim', style: 'font-size:var(--fs-1)' }, 'promised vs forecast')), body);
|
|
334
|
-
const draw = (rows, err) => {
|
|
335
|
-
if (err) { body.replaceChildren(el('p', { class: 'dim mono', style: 'font-size:var(--fs-2)', role: 'status' }, 'The initiatives could not be read: ' + err)); return; }
|
|
336
|
-
if (!rows.length) { body.replaceChildren(el('div', { class: 'fold' }, c3ic('moon', 'sm'), 'No initiative has a promised date yet, so there is nothing to compare with the forecast.')); return; }
|
|
337
|
-
if (rows.some((g) => g.pulse)) { const parts = mockPulse(rows, S.today, null); body.replaceChildren(...parts); inlineRows(parts[1], rows, true); return; } // demo: the mockup's pulse (its own colours, reasons and mini timelines)
|
|
338
|
-
const noPlan = rows.filter((g) => g.status === 'no plan').length;
|
|
339
|
-
rows = rows.filter((g) => g.status !== 'no plan');
|
|
340
|
-
if (!rows.length) { body.replaceChildren(el('div', { class: 'fold' }, c3ic('moon', 'sm'), 'No initiative has a promised date yet, so there is nothing to compare with the forecast.'), noPlan ? el('p', { class: 'dim mono', style: 'font-size:var(--fs-2)' }, noPlan + ' initiatives have no plan date.') : null); return; }
|
|
341
|
-
const by = {};
|
|
342
|
-
rows.forEach((g) => { const k = PST[g.status] ? g.status : 'no plan'; by[k] = (by[k] || 0) + 1; });
|
|
343
|
-
const bar = el('div', { class: 'pbs', role: 'group', 'aria-label': 'Status of initiatives' },
|
|
344
|
-
...Object.keys(by).map((k) => el('span', { style: 'flex:' + by[k] + ';height:10px;border-radius:5px;background:' + PST[k][2], title: by[k] + ' ' + PST[k][1].toLowerCase(), 'aria-label': by[k] + ' ' + PST[k][1].toLowerCase() })));
|
|
345
|
-
const end = (o) => (o && (o.end || o.start)) || null;
|
|
346
|
-
const rowEl = (g) => {
|
|
347
|
-
const k = PST[g.status] ? g.status : 'no plan'; const f = end(g.forecast); const p = g.promised || null;
|
|
348
|
-
const why = p ? 'Forecast ' + (f || 'not set') + ' vs promised ' + p : 'No promised date' + (f ? '; forecast ' + f : '');
|
|
349
|
-
const label = 'Show details: ' + (g.title || g.id);
|
|
350
|
-
return row({ title: g.title || g.id, meta: [why], lead: [el('span', { class: 'dotc ' + PST[k][0] })],
|
|
351
|
-
trail: [el('span', { class: 'mono pst ' + PST_CLS[k] }, PST[k][1] + (g.slip_days > 0 ? ' +' + g.slip_days + ' d' : ''))],
|
|
352
|
-
onOpen: () => {}, openLabel: label, compact: true, attrs: { class: 'prow' },
|
|
353
|
-
openAttrs: { 'data-a': 'pulsexp', 'data-c3pg-prow': g.id, 'aria-label': label } });
|
|
354
|
-
};
|
|
355
|
-
const list = el('div', null, ...rows.slice(0, 8).map(rowEl)); inlineRows(list, rows, false);
|
|
356
|
-
body.replaceChildren(bar, list, rows.length > 8 ? el('div', { class: 'dim mono pnote' }, '+' + (rows.length - 8) + ' more in the Calendar tab') : null, noPlan ? el('div', { class: 'dim mono pnote' }, noPlan + ' more have no plan date.') : null);
|
|
357
|
-
};
|
|
358
|
-
readQuarter().then((j) => {
|
|
359
|
-
if (!j || j.ok === false) draw([], (j && j.error) || 'unreadable'); else { S.today = j.today || ''; draw(j.gantt || []); }
|
|
360
|
-
}).catch((e) => draw([], String((e && e.message) || e)));
|
|
361
|
-
return box;
|
|
362
|
-
}
|
|
363
|
-
|
|
247
|
+
/* ── the Briefing tab: one column, the brief ──
|
|
248
|
+
* In order: the headline deck, Today (c3-brief-today.js), Needs you (c3-brief-needs.js) and Portfolio pulse (c3-brief-pulse.js). The ribbon and the embedded calendar are not here:
|
|
249
|
+
* the calendar is the Calendar tab. The rows below Needs you (drafts, handled, what to stop) and the data-trust card are the briefing's own, when it carries them (the demo's). */
|
|
364
250
|
function briefTab(pane) {
|
|
365
|
-
const
|
|
366
|
-
const deckHost = el('div', { 'data-c3pg': 'deck-host' });
|
|
251
|
+
const col = el('div', { class: 'bcol l' });
|
|
252
|
+
const deckHost = el('div', { 'data-c3pg': 'deck-host' });
|
|
367
253
|
const rvHost = el('div', { 'data-c3pg': 'review-host' }); const hdHost = el('div', { 'data-c3pg': 'handled-host' }); const trHost = el('div', { 'data-c3pg': 'trust-host' }); const ftHost = el('div'); const stHost = el('div', { 'data-c3pg': 'stop-host' }); S.stopHost = stHost; S.needsBox = null;
|
|
368
254
|
S.deckHost = deckHost;
|
|
369
255
|
let sig = '';
|
|
@@ -374,24 +260,16 @@ function briefTab(pane) {
|
|
|
374
260
|
stHost.replaceChildren(...[stopCard(b && b.stop)].filter(Boolean)); trHost.replaceChildren(...(b && b.trust ? [trustCard(b.trust)] : [])); ftHost.replaceChildren(...(b && b.foot ? [footLine(b.foot)] : []));
|
|
375
261
|
if (S.why) whyMark();
|
|
376
262
|
});
|
|
377
|
-
S.needsBox =
|
|
378
|
-
|
|
379
|
-
pane.append(el('div', { class: 'brief' }, el('div', { class: 'bcols' },
|
|
263
|
+
S.needsBox = needsSection(S);
|
|
264
|
+
col.append(deckHost, todaySection(), S.needsBox, rvHost, hdHost, stHost, pulse(S), trHost);
|
|
265
|
+
pane.append(el('div', { class: 'brief one' }, el('div', { class: 'bcols' }, col), ftHost));
|
|
380
266
|
mountBriefing(deckHost, { noTicker: true, onLens: lensChanged });
|
|
381
|
-
|
|
267
|
+
loadBriefPage();
|
|
382
268
|
}
|
|
383
269
|
|
|
384
|
-
/* The day-part switch
|
|
385
|
-
function ribbonGo(label) {
|
|
386
|
-
const b = [...S.panes.brief.querySelectorAll('[data-cv="ribbon"] .seg button')].find((x) => x.textContent.trim() === label);
|
|
387
|
-
if (b) b.click();
|
|
388
|
-
}
|
|
270
|
+
/* The day-part switch: Reflect shows "Carries over" and "What I could stop" (the mockup's vBrief, line 1470). */
|
|
389
271
|
function lensChanged(l) {
|
|
390
|
-
const rf = l === 'Reflect'; if (S.stopHost) S.stopHost.hidden = !rf; setNeedsTitle(S.needsBox, rf);
|
|
391
|
-
const cur = S.panes && S.panes.brief ? S.panes.brief.querySelector('[data-cv="ribbon"] .seg [aria-pressed="true"]') : null;
|
|
392
|
-
const on = cur ? cur.textContent.trim() : '';
|
|
393
|
-
if (l === 'Reflect' && on === 'Today') { S.rAuto = true; ribbonGo('Week'); }
|
|
394
|
-
else if (l !== 'Reflect' && S.rAuto) { S.rAuto = false; ribbonGo('Today'); }
|
|
272
|
+
const rf = l === 'Reflect'; if (S.stopHost) S.stopHost.hidden = !rf; setNeedsTitle(S.needsBox, rf);
|
|
395
273
|
}
|
|
396
274
|
|
|
397
275
|
/* ── global: where a notification goes, the person sheet, the palette and the keys ── */
|
|
@@ -502,11 +380,6 @@ function onKey(e) {
|
|
|
502
380
|
if (rows[ni]) rows[ni].focus();
|
|
503
381
|
return;
|
|
504
382
|
}
|
|
505
|
-
if ('+=-_'.includes(e.key) && e.key.length === 1) {
|
|
506
|
-
const b = S.panes.brief.querySelector('[data-cv="ribbon"] [aria-label^="Zoom ' + (e.key === '+' || e.key === '=' ? 'in' : 'out') + '"]');
|
|
507
|
-
e.stopPropagation(); if (b && !b.disabled) b.click();
|
|
508
|
-
return;
|
|
509
|
-
}
|
|
510
383
|
if (cur && e.key.length === 1 && 'enar'.includes(e.key)) {
|
|
511
384
|
e.stopPropagation(); e.preventDefault();
|
|
512
385
|
const api = rowApi.get(cur); const draft = cur.classList.contains('drow');
|
|
@@ -611,7 +484,7 @@ function draftsTab(pane) {
|
|
|
611
484
|
});
|
|
612
485
|
}
|
|
613
486
|
|
|
614
|
-
const BUILD = { brief: briefTab, cal: (p) => mountCalendarViews(p, { view: '
|
|
487
|
+
const BUILD = { brief: briefTab, cal: (p) => mountCalendarViews(p, { view: 'week', page: true, scope: sc('cal') }), work: (p) => { const plan = planNode(sc('work') && 'work:triage'); mountPmWork(p, { plan, onLens: (l) => { if (DEMO) setPlanScope(plan, 'work:' + l); } }); }, init: initTab, rep: repTab };
|
|
615
488
|
|
|
616
489
|
function showTab(id, push) {
|
|
617
490
|
if (!BUILD[id]) id = 'brief';
|
|
@@ -633,6 +506,11 @@ function showTab(id, push) {
|
|
|
633
506
|
async function workCount() {
|
|
634
507
|
const j = await pmGet('/api/pm-items').catch(() => null);
|
|
635
508
|
if (!j || !j.ok || !j.lists) return;
|
|
509
|
+
if (j.counts && typeof j.counts.inbox === 'number') { // the Work page's own counts: what is to process (inbox) plus what is on today
|
|
510
|
+
const w = j.counts.inbox + (Number(j.counts.today) || 0);
|
|
511
|
+
S.workBdg.textContent = String(w); S.workBdg.hidden = w === 0;
|
|
512
|
+
return;
|
|
513
|
+
}
|
|
636
514
|
const n = (j.lists.triage || []).length + (S.demo ? 0 : (j.lists.today || []).length); // the mockup's Work badge counts what is to triage
|
|
637
515
|
S.workBdg.textContent = String(n); S.workBdg.hidden = n === 0;
|
|
638
516
|
}
|
|
@@ -18,6 +18,7 @@ import { renderCase } from './c3-case.js';
|
|
|
18
18
|
import { makeXp, attachExpand } from './c3-expand.js';
|
|
19
19
|
import { mountQuarter, mountYear, dispose as disposeStrategy } from './c3-cal-strategy.js'; // the Quarter and Year panes
|
|
20
20
|
import { simDock, simStart, simState, isDemo } from './shell-recording.js';
|
|
21
|
+
import { drawCalendarPage } from './c3-calendar.js'; // the Calendar tab as a page about time (ctx.page)
|
|
21
22
|
|
|
22
23
|
/* ── shared state of the /c3.html page (console3 wave C3) ──────────────────────────────────────────────────────────
|
|
23
24
|
* `live` holds every mounted instance, so a press in the Briefing's ribbon can select a meeting on the Calendar tab's instance.
|
|
@@ -28,7 +29,8 @@ let SHARED_SEL = null; // a meeting chosen on the Briefing, read when the Cale
|
|
|
28
29
|
const IX = () => (typeof window !== 'undefined' && window.__c3calix) || null;
|
|
29
30
|
const baseId = (e) => String((e && e.id) || '').split('@')[0];
|
|
30
31
|
const gotoTab = (id) => { const b = document.querySelector('[data-c3-tab="' + id + '"]'); if (b) b.click(); };
|
|
31
|
-
const isC3 = (r) => !!(r && r.ctx && (r.ctx.ribbon || r.ctx.plan));
|
|
32
|
+
const isC3 = (r) => !!(r && r.ctx && (r.ctx.ribbon || r.ctx.plan || r.ctx.page));
|
|
33
|
+
const isCalTab = (x) => !!(x && x.ctx && (x.ctx.plan || x.ctx.page)); // the Calendar tab's own instance (the older mount passes plan, the page passes page)
|
|
32
34
|
|
|
33
35
|
const NS = 'http://www.w3.org/2000/svg';
|
|
34
36
|
const VIEWS = [['day', 'Day'], ['week', 'Week'], ['month', 'Month'], ['quarter', 'Quarter'], ['year', 'Year']];
|
|
@@ -564,7 +566,7 @@ const todayOf = (r) => (r.data && r.data.today) || todayStr();
|
|
|
564
566
|
/* a day (and a meeting) on the Calendar tab's own instance; if that tab has not mounted yet its instance reads PENDING when it does */
|
|
565
567
|
let PENDING = null;
|
|
566
568
|
function openDay(date, sel) {
|
|
567
|
-
const cal = [...live].find(
|
|
569
|
+
const cal = [...live].find(isCalTab);
|
|
568
570
|
if (cal) { cal.sel = sel || null; cal.phase = null; go(cal.host, cal, { view: 'day', date, anim: 'zi' }); }
|
|
569
571
|
else PENDING = { date, sel: sel || null };
|
|
570
572
|
gotoTab('cal');
|
|
@@ -878,6 +880,7 @@ function weekHead(data) {
|
|
|
878
880
|
|
|
879
881
|
function draw(host, r) {
|
|
880
882
|
if (r.ctx && r.ctx.ribbon) { r.root.replaceChildren(ribbonCard(host, r)); if (!r.loading) r.anim = null; return; }
|
|
883
|
+
if (r.ctx && r.ctx.page) { disposeStrategy(r.root); r.root.replaceChildren(drawCalendarPage(host, r, PAGE)); if (!r.loading) r.anim = null; return; } // the Calendar tab (c3-calendar.js): no deck, no due list, no strategy lens
|
|
881
884
|
const phone = r.root.classList.contains('ph');
|
|
882
885
|
const head = bar(host, r, phone);
|
|
883
886
|
let body;
|
|
@@ -904,6 +907,10 @@ function draw(host, r) {
|
|
|
904
907
|
r.root.replaceChildren(head, body);
|
|
905
908
|
}
|
|
906
909
|
|
|
910
|
+
/* What the Calendar page (c3-calendar.js) reuses from this file: the zoom bar with the Today chip, the reads and the date helpers. */
|
|
911
|
+
const PAGE = { bar, go: (host, r, change) => go(host, r, change), redraw: (host, r) => draw(host, r), shift, dayLabel, timeOf, endH, hhmm, baseId, dowOf, MN, DN,
|
|
912
|
+
gotoTab, goInitiative, openInit };
|
|
913
|
+
|
|
907
914
|
/* Change the view or the date and read again. anim names the mockup's transition (.zi, .zo, .sn, .sp, console3.css). */
|
|
908
915
|
function go(host, r, change) {
|
|
909
916
|
if (change.view) r.view = change.view;
|
|
@@ -967,6 +974,7 @@ function wire(host, r) {
|
|
|
967
974
|
if (!root.isConnected || !root.offsetParent) return; // another tab is showing
|
|
968
975
|
const t = e.target; if (t && t.closest && t.closest('input,select,textarea,[contenteditable="true"]')) return;
|
|
969
976
|
if (document.querySelector('[data-shell="sheet"]')) return; // a sheet is open
|
|
977
|
+
if (!root.closest('[data-shell="calpop"]') && document.querySelector('[data-shell="calpop"]')) return; // the calendar popup is open: it takes the keys, not the tab behind it
|
|
970
978
|
if ((e.key === '+' || e.key === '=') && zoomBy(-1)) e.preventDefault();
|
|
971
979
|
else if ((e.key === '-' || e.key === '_') && zoomBy(1)) e.preventDefault();
|
|
972
980
|
else if (rib) return;
|
|
@@ -981,7 +989,7 @@ function wire(host, r) {
|
|
|
981
989
|
let simOnWin = false;
|
|
982
990
|
function installSim() {
|
|
983
991
|
if (simOnWin || typeof window === 'undefined') return; simOnWin = true;
|
|
984
|
-
const calInst = () => [...live].filter((x) => x
|
|
992
|
+
const calInst = () => [...live].filter((x) => isCalTab(x) && x.root.isConnected);
|
|
985
993
|
window.addEventListener('c3-sim-rec', () => calInst().forEach((x) => { if (selEvent(x)) refreshSel(x.host, x); }));
|
|
986
994
|
window.addEventListener('c3-sim-open', () => { gotoTab('cal'); calInst().forEach((x) => { if (x.view !== 'day') x.view = 'day'; x.phase = 'during'; if (x.data && x.data.unit === 'day' && x.data.range.start === x.data.range.end) refreshSel(x.host, x); else go(x.host, x, { view: 'day', date: todayOf(x) }); }); });
|
|
987
995
|
}
|
|
@@ -7932,4 +7932,5 @@
|
|
|
7932
7932
|
containers). The tab strip and the scratchpad are drawn with inline radii (workspace-cockpit-nav); the inline radii
|
|
7933
7933
|
(8px tab strip, 6px controls) stay. A tab's colour dot is a dot and keeps its circle. */
|
|
7934
7934
|
|
|
7935
|
+
/* -- layouts · .cal3- the console3 Calendar page (calendar-time-page): its rules sit in console3.css beside the .vday rules they extend -- */
|
|
7935
7936
|
/* -- end of the layout sections: add nothing below this line -- */
|
|
@@ -491,6 +491,117 @@
|
|
|
491
491
|
.c3 .sgb[aria-pressed="true"]{background:var(--accw);border-color:var(--acc);color:var(--foreground)}
|
|
492
492
|
.c3 .vday .vb.past{opacity:.45}
|
|
493
493
|
.c3 .vday .vb.skip{background:repeating-linear-gradient(135deg,var(--muted) 0 6px,transparent 6px 12px);color:var(--muted-foreground);text-decoration:line-through;box-shadow:none;outline:1px dashed var(--ring)}
|
|
494
|
+
/* console3.css addition: the Calendar page (c3-calendar.js, initiative calendar-time-page). Classes start with cal3-, colours are tokens.
|
|
495
|
+
* The controls are primitives (button()), so each rule below sets the box itself: it wins over components.css when that sheet is loaded. */
|
|
496
|
+
.c3 .cal3{display:grid;gap:var(--sp-3);min-width:0}
|
|
497
|
+
.c3 .cal3-head{display:flex;gap:4px 12px;align-items:baseline;flex-wrap:wrap}
|
|
498
|
+
.c3 .cal3-head h2{margin:0;font:600 var(--fs-5) var(--sans)}
|
|
499
|
+
.c3 .cal3 .calbar{margin-bottom:0}
|
|
500
|
+
.c3 .cal3-chips{display:flex;gap:6px;flex-wrap:wrap;align-items:center}
|
|
501
|
+
.c3 .cal3 button.cal3-chip{display:inline-flex;align-items:center;gap:6px;height:auto;min-height:30px;padding:3px 10px;border:1px solid var(--border);border-radius:8px;background:var(--card);color:var(--muted-foreground);font:500 var(--fs-2) var(--sans);cursor:pointer;white-space:nowrap}
|
|
502
|
+
.c3 .cal3 button.cal3-chip>span{display:inline-flex;align-items:center;gap:6px}
|
|
503
|
+
.c3 .cal3 button.cal3-chip[aria-pressed="true"]{background:var(--accw);border-color:var(--acc);color:var(--foreground)}
|
|
504
|
+
.c3 .cal3-chip .cal3-n{font:var(--fs-1) var(--mono);color:var(--muted-foreground)}
|
|
505
|
+
.c3 .cal3-sep{width:1px;align-self:stretch;background:var(--border);margin:0 4px}
|
|
506
|
+
.c3 .cal3-sw{display:inline-block;flex:none;width:10px;height:10px;border-radius:0;background:var(--muted-foreground)}
|
|
507
|
+
.c3 .cal3-sw-meetings{background:var(--acc)}
|
|
508
|
+
.c3 .cal3-sw-milestones{background:var(--foreground)}
|
|
509
|
+
.c3 .cal3-sw-releases{background:transparent;border:2px solid var(--acc)}
|
|
510
|
+
.c3 .cal3-sw-reports{background:var(--muted-foreground)}
|
|
511
|
+
.c3 .cal3-sw-mine{background:transparent;border:1px dashed var(--foreground)}
|
|
512
|
+
.c3 .cal3-wrap{display:grid;grid-template-columns:minmax(0,1fr);gap:var(--sp-3);align-items:start}
|
|
513
|
+
@container (min-width:1100px){.c3 .cal3-wrap{grid-template-columns:minmax(0,1fr) 340px}}
|
|
514
|
+
.c3 .cal3-main,.c3 .cal3-side{display:grid;gap:var(--sp-3);min-width:0;align-content:start}
|
|
515
|
+
.c3 .cal3-scroll{overflow-x:auto;min-width:0}
|
|
516
|
+
/* a marker: glyph and short title; the left edge carries the tone */
|
|
517
|
+
.c3 .cal3 button.cal3-mk{--cal3-tc:var(--muted-foreground);display:flex;align-items:center;width:100%;min-width:0;height:auto;min-height:22px;padding:1px 6px;border:0;border-left:3px solid var(--cal3-tc);border-radius:6px;background:var(--muted);color:var(--foreground);font:500 var(--fs-1)/1.4 var(--sans);text-align:left;cursor:pointer;white-space:nowrap;overflow:hidden;justify-content:flex-start}
|
|
518
|
+
.c3 .cal3 button.cal3-mk>span{display:flex;gap:4px;align-items:center;min-width:0;overflow:hidden}
|
|
519
|
+
.c3 .cal3-mk .ic{flex:none;color:var(--cal3-tc)}
|
|
520
|
+
.c3 .cal3-mk .cal3-mk-t{overflow:hidden;text-overflow:ellipsis;min-width:0}
|
|
521
|
+
.c3 .cal3 button.cal3-k-milestone,.c3 .cal3 button.cal3-k-due{--cal3-tc:var(--foreground)}
|
|
522
|
+
.c3 .cal3 button.cal3-k-release{--cal3-tc:var(--acc)}
|
|
523
|
+
.c3 .cal3 button.cal3-k-report{--cal3-tc:var(--muted-foreground)}
|
|
524
|
+
.c3 .cal3 button.cal3-k-own{background:transparent;box-shadow:inset 0 0 0 1px var(--border)}
|
|
525
|
+
.c3 .cal3 button.cal3-tone-warn{--cal3-tc:var(--warning)}
|
|
526
|
+
.c3 .cal3 button.cal3-tone-bad{--cal3-tc:var(--destructive)}
|
|
527
|
+
.c3 .cal3 button.cal3-mk.sel{outline:2px solid var(--foreground);outline-offset:1px}
|
|
528
|
+
.c3 .tag.cal3-tone-warn{color:var(--warning)}
|
|
529
|
+
.c3 .tag.cal3-tone-bad{color:var(--destructive)}
|
|
530
|
+
.c3 .tag.cal3-up{color:var(--acc)}
|
|
531
|
+
.c3 .cal3-more,.c3 .cal3-fcnt{font:var(--fs-1) var(--mono);color:var(--muted-foreground)}
|
|
532
|
+
.c3 .cal3-cnt{font:var(--fs-1) var(--mono);color:var(--acc)}
|
|
533
|
+
/* Day and Week: the timeline, its day heads and the all-day marker strip */
|
|
534
|
+
.c3 .cal3-tg{min-width:0}
|
|
535
|
+
.c3 .cal3-tg:not(.one){min-width:620px}
|
|
536
|
+
.c3 .cal3-row{display:grid;grid-template-columns:44px repeat(var(--cal3-n),minmax(0,1fr))}
|
|
537
|
+
.c3 .cal3-dhead,.c3 .cal3-strip{border-bottom:1px solid var(--border)}
|
|
538
|
+
.c3 .cal3-dh{padding:4px;border-left:1px solid var(--border);min-width:0;font:500 var(--fs-2) var(--mono)}
|
|
539
|
+
.c3 .cal3-dh.today b,.c3 .cal3-dh.today button.cal3-dbtn{color:var(--acc)}
|
|
540
|
+
.c3 .cal3-gut{font:var(--fs-1) var(--mono);color:var(--muted-foreground);padding:6px 4px}
|
|
541
|
+
.c3 .cal3-sc{border-left:1px solid var(--border);padding:3px;display:grid;gap:2px;align-content:start;min-height:28px;min-width:0}
|
|
542
|
+
.c3 .cal3-none{font:var(--fs-1) var(--mono);color:var(--muted-foreground);padding:4px}
|
|
543
|
+
.c3 .cal3-hours{position:relative;height:var(--cal3-hgt)}
|
|
544
|
+
.c3 .cal3-hours span{position:absolute;top:var(--cal3-y);right:6px;font:var(--fs-1) var(--mono);color:var(--muted-foreground)}
|
|
545
|
+
.c3 .vday.cal3-col{height:var(--cal3-hgt);margin-top:0;border-left:1px solid var(--border);background:repeating-linear-gradient(to bottom,var(--border) 0 1px,transparent 1px var(--cal3-pph))}
|
|
546
|
+
.c3 .vday.cal3-col.we{background-color:var(--muted)}
|
|
547
|
+
.c3 .vday.cal3-col.today{background-color:var(--accw)}
|
|
548
|
+
.c3 .vday .cal3-free{left:2px;right:2px;top:var(--cal3-y);height:var(--cal3-h);display:flex;flex-direction:column;align-items:flex-start;gap:2px;padding:4px 6px;overflow:hidden;border:1px dashed var(--ring);z-index:1}
|
|
549
|
+
.c3 .vday .cal3-free b{font:500 var(--fs-1) var(--mono);color:var(--foreground)}
|
|
550
|
+
.c3 .vday .cal3-free span{font:var(--fs-1)/1.3 var(--sans);color:var(--muted-foreground)}
|
|
551
|
+
.c3 .vday button.cal3-ev{top:var(--cal3-y);height:var(--cal3-h);min-height:0;left:calc(2px + (100% - 4px) * var(--cal3-l) / var(--cal3-lc));right:auto;width:calc((100% - 4px) / var(--cal3-lc) - 2px);display:block;padding:3px 8px;z-index:2;white-space:nowrap;cursor:pointer}
|
|
552
|
+
.c3 .vday button.cal3-ev>span{display:block;overflow:hidden}
|
|
553
|
+
.c3 .vday .cal3-ev b{display:block;overflow:hidden;text-overflow:ellipsis;font-weight:500}
|
|
554
|
+
.c3 .vday .cal3-now{left:0;top:var(--cal3-y)}
|
|
555
|
+
.c3 .cal3 button.cal3-allday{display:block;width:100%;height:auto;min-height:22px;padding:1px 6px;border:0;border-radius:6px;background:var(--acc);color:var(--on-accent);font:500 var(--fs-1)/1.4 var(--sans);text-align:left;overflow:hidden;white-space:nowrap;cursor:pointer}
|
|
556
|
+
.c3 .cal3 button.cal3-dbtn,.c3 .cal3 button.cal3-dn{display:inline-flex;align-items:center;height:auto;min-height:24px;padding:2px 6px;border:0;border-radius:6px;background:transparent;color:var(--foreground);font:500 var(--fs-2) var(--mono);cursor:pointer;justify-content:flex-start}
|
|
557
|
+
/* Month */
|
|
558
|
+
.c3 .cal3-month{display:grid;grid-template-columns:repeat(7,minmax(0,1fr));gap:4px}
|
|
559
|
+
.c3 .cal3-wd{font:500 var(--fs-1) var(--mono);color:var(--muted-foreground);text-align:center;padding:2px}
|
|
560
|
+
.c3 .cal3-mc{border:1px solid var(--border);border-radius:8px;background:var(--background);min-height:96px;padding:4px;display:grid;gap:2px;align-content:start;min-width:0;overflow:hidden}
|
|
561
|
+
.c3 .cal3-mc.out{border:0;background:transparent}
|
|
562
|
+
.c3 .cal3-mc.we{background:var(--muted)}
|
|
563
|
+
.c3 .cal3-mc.today{border-color:var(--acc);box-shadow:0 0 0 1px var(--acc)}
|
|
564
|
+
/* Quarter and Year */
|
|
565
|
+
.c3 .cal3-quarter{display:grid}
|
|
566
|
+
.c3 .cal3-qrow{display:grid;grid-template-columns:minmax(150px,auto) auto minmax(0,1fr);gap:8px;align-items:center;padding:6px 4px;border-bottom:1px solid var(--border);min-width:0}
|
|
567
|
+
.c3 .cal3-qrow.now,.c3 .cal3-ym.now{background:var(--accw)}
|
|
568
|
+
.c3 .cal3-qmk{display:flex;flex-wrap:wrap;gap:3px;min-width:0}
|
|
569
|
+
.c3 .cal3-qmk button.cal3-mk{width:auto;max-width:100%}
|
|
570
|
+
.c3 .cal3-counts{display:flex;gap:4px;flex-wrap:wrap}
|
|
571
|
+
.c3 .cal3-year{display:grid;grid-template-columns:repeat(auto-fill,minmax(200px,1fr));gap:8px}
|
|
572
|
+
.c3 .cal3-ym{border:1px solid var(--border);border-radius:8px;padding:8px;display:grid;gap:6px;align-content:start;min-width:0}
|
|
573
|
+
@container (max-width:640px){
|
|
574
|
+
.c3 .cal3-mk.compact .cal3-mk-t{display:none}
|
|
575
|
+
.c3 .cal3-mc{min-height:64px;padding:2px}
|
|
576
|
+
.c3 .cal3-qrow{grid-template-columns:minmax(0,1fr)}
|
|
577
|
+
}
|
|
578
|
+
/* the detail column */
|
|
579
|
+
.c3 .cal3-dt{display:flex;align-items:center;gap:8px}
|
|
580
|
+
.c3 .cal3-dt h3{flex:1}
|
|
581
|
+
.c3 .cal3-title{font:600 var(--fs-4) var(--sans)}
|
|
582
|
+
.c3 .cal3-when{font-size:var(--fs-2)}
|
|
583
|
+
.c3 .cal3-ctx{display:grid;gap:6px}
|
|
584
|
+
.c3 .cal3-ctx h4{margin:0;font:600 var(--fs-2) var(--sans);color:var(--foreground)}
|
|
585
|
+
.c3 .cal3-cl{list-style:none;margin:0;padding:0;display:grid;gap:6px}
|
|
586
|
+
.c3 .cal3-ci{display:flex;flex-wrap:wrap;gap:4px 8px;align-items:baseline;font-size:var(--fs-2);padding-bottom:6px;border-bottom:1px solid var(--border)}
|
|
587
|
+
.c3 .cal3-ct{flex:1 1 160px;min-width:0}
|
|
588
|
+
.c3 .cal3-at{font-size:var(--fs-1)}
|
|
589
|
+
.c3 .cal3-note{margin:0;font-size:var(--fs-2)}
|
|
590
|
+
.c3 .cal3 a.cal3-ref{display:inline-flex;gap:4px;align-items:center;color:var(--acc);font:500 var(--fs-2) var(--sans);text-decoration:underline;text-underline-offset:2px}
|
|
591
|
+
.c3 .cal3-lane{display:grid;grid-template-columns:auto auto minmax(0,1fr);gap:8px;align-items:center;font-size:var(--fs-2)}
|
|
592
|
+
.c3 .cal3-why{text-align:right}
|
|
593
|
+
.c3 .cal3 button.cal3-close{margin-left:auto;height:auto;min-height:24px;padding:2px 8px;border:1px solid var(--border);border-radius:6px;background:transparent;color:var(--muted-foreground);font:500 var(--fs-1) var(--mono);cursor:pointer}
|
|
594
|
+
.c3 .cal3 button:focus-visible,.c3 .cal3 a:focus-visible{outline:2px solid color-mix(in oklab, var(--ring) 50%, var(--foreground));outline-offset:2px}
|
|
595
|
+
@media (hover:hover){
|
|
596
|
+
.c3 .cal3 button.cal3-chip:hover{border-color:var(--ring)}
|
|
597
|
+
.c3 .cal3 button.cal3-mk:hover{background:var(--accw)}
|
|
598
|
+
}
|
|
599
|
+
@media (pointer:coarse){
|
|
600
|
+
.c3 .cal3 button.cal3-chip,.c3 .cal3 button.cal3-mk,.c3 .cal3 button.cal3-dn,.c3 .cal3 button.cal3-dbtn,.c3 .cal3 button.cal3-close,.c3 .cal3 button.cal3-allday,.c3 .cal3 a.cal3-ref{min-height:44px}
|
|
601
|
+
}
|
|
602
|
+
@media (prefers-reduced-motion:reduce){
|
|
603
|
+
.c3 .cal3 *{animation:none;transition:none}
|
|
604
|
+
}
|
|
494
605
|
.c3 .cmain{display:flex;flex-direction:column;gap:8px;min-height:0}
|
|
495
606
|
.c3 .pdots{display:flex;gap:6px;flex-wrap:wrap}
|
|
496
607
|
.c3 .pdots i{width:26px;height:26px;border-radius:50%;display:grid;place-items:center;border:1px dashed var(--ring);color:var(--muted-foreground)}
|
|
@@ -1101,6 +1212,13 @@
|
|
|
1101
1212
|
.c3 .sheet:focus{outline:none}
|
|
1102
1213
|
.c3 .sheet.bs.dragging{transition:none}
|
|
1103
1214
|
.c3 .sheet .sh2 .ib{flex:none}
|
|
1215
|
+
/* the calendar popup (c3-calpop.js): the sheet, centred and wide on a desktop, the whole screen on a phone */
|
|
1216
|
+
.c3 .sheet.calpop{left:12px;right:12px;margin-inline:auto;width:min(1100px,calc(100% - 24px))}
|
|
1217
|
+
.c3 .sheet.calpop .sb{padding:var(--sp-3);min-width:0}
|
|
1218
|
+
.c3 .calpop-host{min-width:0;max-width:100%}
|
|
1219
|
+
.c3.ph .sheet.calpop{top:0;left:0;right:0;bottom:0;width:auto;max-height:none;border-radius:0;margin:0}
|
|
1220
|
+
.c3.ph .sheet.bs.calpop{max-height:none;animation:none}
|
|
1221
|
+
.c3 .sheet.calpop .ib,.c3 .sheet.calpop .seg button,.c3 .sheet.calpop .tdy{min-height:44px;min-width:44px}
|
|
1104
1222
|
@media (prefers-reduced-motion:reduce){.c3 .sheet,.c3 .scrim,.c3.ph .sheet.bs{animation:none}}
|
|
1105
1223
|
/* a slide that cannot be used: the action goes outside and no outbox is connected. The reason sits under it (c3-case.js). */
|
|
1106
1224
|
.c3 .slt.off{opacity:.55;--tc:var(--muted-foreground)}
|
|
@@ -1484,6 +1602,42 @@
|
|
|
1484
1602
|
.c3 .psess:active{transform:scale(.93)}
|
|
1485
1603
|
@media (max-width:760px){.c3 .psess{min-height:44px}}
|
|
1486
1604
|
.c3 .psess .c{font:var(--fs-1) var(--mono)}
|
|
1605
|
+
/* Briefing as the brief (initiative briefing-brief): one column; Today agenda; own-item rows of Needs you; inline Portfolio pulse */
|
|
1606
|
+
.c3 .brief.one{max-width:900px}
|
|
1607
|
+
.c3 .brief.one .bcols{grid-template-columns:minmax(0,1fr)}
|
|
1608
|
+
.c3 .brief.one .bcol{display:grid;gap:16px;min-width:0}
|
|
1609
|
+
.c3 .c3s2{font-size:var(--fs-2)}
|
|
1610
|
+
.c3 .c3s3{font-size:var(--fs-3)}
|
|
1611
|
+
.c3 .ki.t-bad{color:var(--destructive)}
|
|
1612
|
+
.c3 .ki.t-warn{color:var(--warning)}
|
|
1613
|
+
.c3 .ki.t-ink{color:var(--foreground)}
|
|
1614
|
+
.c3 .trow{display:grid;grid-template-columns:72px minmax(0,1fr);gap:10px;padding:10px 6px;border-bottom:1px solid var(--border);border-radius:8px}
|
|
1615
|
+
.c3 .trow.past{opacity:.55}
|
|
1616
|
+
.c3 .trow.now,.c3 .trow.next{background:var(--muted)}
|
|
1617
|
+
.c3 .trow .tm{font:500 var(--fs-3) var(--mono)}
|
|
1618
|
+
.c3 .trow .tb{display:grid;gap:6px;min-width:0}
|
|
1619
|
+
.c3 .trow .tt{font-size:var(--fs-3)}
|
|
1620
|
+
.c3 .trow .tcols{display:grid;grid-template-columns:repeat(2,minmax(0,1fr));gap:12px}
|
|
1621
|
+
.c3 .trow .lab{font-size:var(--fs-1);letter-spacing:.06em;text-transform:uppercase;color:var(--muted-foreground)}
|
|
1622
|
+
.c3 .trow ul{margin:2px 0 0;padding:0;list-style:none;display:grid;gap:4px;font-size:var(--fs-2)}
|
|
1623
|
+
.c3 .trow p{margin:2px 0 0}
|
|
1624
|
+
.c3 .ip{display:grid;gap:8px;padding:8px 0 4px}
|
|
1625
|
+
.c3 .ip .looks{display:flex;flex-wrap:wrap;gap:8px;align-items:center;font-size:var(--fs-2);padding:8px;border-radius:8px;background:var(--muted)}
|
|
1626
|
+
.c3 .ip .ioutcome{width:100%;min-height:36px;padding:6px 10px;border:1px solid var(--border);border-radius:6px;background:var(--card);color:var(--foreground);font:inherit;font-size:var(--fs-3)}
|
|
1627
|
+
.c3 .ip .iacts{display:flex;flex-wrap:wrap;gap:8px;align-items:center}
|
|
1628
|
+
.c3 .ip .ny{display:flex;flex-wrap:wrap;gap:6px;align-items:center}
|
|
1629
|
+
.c3 .pulsecard{gap:8px}
|
|
1630
|
+
.c3 .pulsehead{display:flex;justify-content:space-between;align-items:center;gap:8px}
|
|
1631
|
+
.c3 .pbs .pb-seg{flex:var(--fr-grow,1);height:10px;border-radius:6px;background:var(--border)}
|
|
1632
|
+
.c3 .pbs .pb-warn{background:var(--warning)}
|
|
1633
|
+
.c3 .pbs .pb-bad{background:var(--destructive)}
|
|
1634
|
+
.c3 .pbs .pb-ok{background:var(--muted-foreground)}
|
|
1635
|
+
.c3 .pwrap{border-radius:8px}
|
|
1636
|
+
@container (max-width:520px){
|
|
1637
|
+
.c3 .trow{grid-template-columns:minmax(0,1fr)}
|
|
1638
|
+
.c3 .trow .tcols{grid-template-columns:minmax(0,1fr)}
|
|
1639
|
+
}
|
|
1640
|
+
.c3.ph .ip .ioutcome{min-height:44px}
|
|
1487
1641
|
|
|
1488
1642
|
/* Time of day (console3 quick fixes R5). data-daypart is set on the page root from the clock: morning, midday, afternoon, evening or night.
|
|
1489
1643
|
* Each part sets two tokens, both very faint: --dp-tint (a wash over the page background, alpha 6% or less) and --dp-warm (the colour of the
|
|
@@ -1545,3 +1699,47 @@
|
|
|
1545
1699
|
.c3 .c3hold .hb.off{opacity:.55;cursor:not-allowed}
|
|
1546
1700
|
.c3 .c3hold .hint{font:var(--fs-1) var(--mono);color:var(--muted-foreground)}
|
|
1547
1701
|
.c3 .c3hold .cq{display:flex;gap:var(--sp-2);align-items:center;flex-wrap:wrap;font:var(--fs-2) var(--mono)}
|
|
1702
|
+
/* ===== the Work page (pm/pm-work-view.js, initiative console3-work-page): Focus, Upcoming by day, the weekly Review, offline work and the
|
|
1703
|
+
* shared actions. Tokens only; corners 6px on a control and 8px on a container. */
|
|
1704
|
+
.c3 .wk-min{min-width:0}
|
|
1705
|
+
.c3 .wk-s{font-size:var(--fs-2)}
|
|
1706
|
+
.c3 .pill.pri{background:var(--foreground);color:var(--background);border-color:var(--foreground)}
|
|
1707
|
+
.c3 .wkq{display:flex;flex-wrap:wrap;gap:var(--sp-2);align-items:center;margin-top:var(--sp-2)}
|
|
1708
|
+
.c3 .wkq-f{display:inline-flex;gap:6px;align-items:center;font-size:var(--fs-2)}
|
|
1709
|
+
.c3 .wkq input[type=date],.c3 .wkq-f input[type=text]{font:inherit;font-size:var(--fs-2);padding:4px 6px;border:1px solid var(--border);background:var(--background);color:var(--foreground);border-radius:6px;min-width:0;max-width:150px}
|
|
1710
|
+
.c3 .tag.wk-off{background:var(--accw);color:var(--acc)}
|
|
1711
|
+
.c3 .tag.wk-nb{background:var(--muted);color:var(--foreground)}
|
|
1712
|
+
.c3 .tag.wk-on{background:var(--acc);color:var(--background)}
|
|
1713
|
+
.c3 .chip2.wk-fl{color:var(--acc)}
|
|
1714
|
+
.c3 .wkoff{display:grid;gap:var(--sp-1);border:1px solid var(--border);border-radius:8px;padding:var(--sp-2) var(--sp-3);margin:var(--sp-2) 0}
|
|
1715
|
+
.c3 .wkoff-n{margin:0;display:flex;gap:6px;align-items:center;font-size:var(--fs-2);color:var(--muted-foreground)}
|
|
1716
|
+
.c3 .wkoff-o{flex:1 1 220px;min-width:0}
|
|
1717
|
+
.c3 .wkoff-o input[type=text]{width:100%}
|
|
1718
|
+
.c3 .wkev{display:flex;flex-wrap:wrap;gap:var(--sp-2);align-items:center;border:1px dashed var(--warning);border-radius:8px;padding:var(--sp-2) var(--sp-3);font-size:var(--fs-2)}
|
|
1719
|
+
.c3 .wkev>.wk-min{flex:1 1 200px}
|
|
1720
|
+
.c3 .wkfg{display:grid;grid-template-columns:repeat(auto-fit,minmax(min(100%,240px),1fr));gap:var(--sp-3)}
|
|
1721
|
+
.c3 .wkfc{border:1px solid var(--border);background:var(--card);border-radius:8px;padding:var(--sp-3);display:grid;gap:var(--sp-2);align-content:start;min-width:0}
|
|
1722
|
+
.c3 .wkfc.on{border-color:var(--acc);background:var(--accw)}
|
|
1723
|
+
.c3 .wkfc-t{font-size:var(--fs-3);line-height:1.3;overflow-wrap:anywhere}
|
|
1724
|
+
.c3 .wkfc-why{margin:0;font-size:var(--fs-2);color:var(--muted-foreground)}
|
|
1725
|
+
.c3 .wkfc-r{margin:0;padding:0;list-style:none;display:grid;gap:2px;font-size:var(--fs-2)}
|
|
1726
|
+
.c3 .wkfc-r li{display:flex;gap:4px;align-items:center;min-width:0}
|
|
1727
|
+
.c3 .wkfc .wkq{margin-top:0}
|
|
1728
|
+
.c3 .wkdays{display:grid}
|
|
1729
|
+
.c3 .wkday h3{margin:0;padding:var(--sp-2) 0 var(--sp-1);font:500 var(--fs-2) var(--mono);color:var(--foreground);display:flex;gap:var(--sp-2);align-items:baseline}
|
|
1730
|
+
.c3 .wkday h3 .dim{font-weight:400}
|
|
1731
|
+
.c3 .wkday-none{color:var(--muted-foreground);font-size:var(--fs-2);padding:0 0 var(--sp-2);border-bottom:1px solid var(--border)}
|
|
1732
|
+
.c3 .wkrv{gap:var(--sp-3)}
|
|
1733
|
+
.c3 .wkrv-p{display:flex;justify-content:space-between;font:var(--fs-2) var(--mono);color:var(--muted-foreground)}
|
|
1734
|
+
.c3 .wkrv-t{margin:0;font:600 var(--fs-4)/1.3 var(--sans);color:var(--foreground);overflow-wrap:anywhere}
|
|
1735
|
+
.c3 .wkrv-x{display:grid;gap:var(--sp-2)}
|
|
1736
|
+
@media (max-width:760px){
|
|
1737
|
+
.c3 .wkq input[type=date],.c3 .wkq-f input[type=text]{min-height:44px;max-width:none}
|
|
1738
|
+
.c3 .wkoff-o input[type=text],.c3 .wkfc input[type=text]{min-height:44px}
|
|
1739
|
+
}
|
|
1740
|
+
|
|
1741
|
+
.c3 .wk-sm{font-size:var(--fs-2)}
|
|
1742
|
+
.c3 .wk-bar{appearance:none;-webkit-appearance:none;width:100%;height:8px;border:0;border-radius:6px;overflow:hidden;background:var(--muted)}
|
|
1743
|
+
.c3 .wk-bar::-webkit-progress-bar{background:var(--muted)}
|
|
1744
|
+
.c3 .wk-bar::-webkit-progress-value{background:var(--acc);border-radius:6px}
|
|
1745
|
+
.c3 .wk-bar::-moz-progress-bar{background:var(--acc);border-radius:6px}
|