fix(fristenrechner): m/paliad#57 — cleanup (Custom labels, forward-workflow root, same-context-twice, Add prefill) #66
@@ -251,6 +251,19 @@ function closeSaveModal() {
|
|||||||
if (modal) modal.style.display = "none";
|
if (modal) modal.style.display = "none";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// preselectedProjectId returns the project the user picked in Step 1
|
||||||
|
// (if any) so the various save/add flows can default their project
|
||||||
|
// pickers to it. Carries through anywhere a "save to Akte" pop-out
|
||||||
|
// renders \u2014 preselection is *only* a default; the picker still
|
||||||
|
// renders every available project and the user can override.
|
||||||
|
// m/paliad#57 part 1: 2026-05-20 user complaint \u2014 "the pre-selected
|
||||||
|
// project should be pre-selected" on Add.
|
||||||
|
function preselectedProjectId(): string {
|
||||||
|
return currentStep1Context.kind === "project" && currentStep1Context.projectId
|
||||||
|
? currentStep1Context.projectId
|
||||||
|
: "";
|
||||||
|
}
|
||||||
|
|
||||||
async function openSaveModal() {
|
async function openSaveModal() {
|
||||||
if (!lastResponse) return;
|
if (!lastResponse) return;
|
||||||
ensureSaveModal();
|
ensureSaveModal();
|
||||||
@@ -267,6 +280,7 @@ async function openSaveModal() {
|
|||||||
sel.style.display = "";
|
sel.style.display = "";
|
||||||
noProjects.style.display = "none";
|
noProjects.style.display = "none";
|
||||||
submit.disabled = false;
|
submit.disabled = false;
|
||||||
|
const preselected = preselectedProjectId();
|
||||||
sel.innerHTML = projects
|
sel.innerHTML = projects
|
||||||
.map((p) => {
|
.map((p) => {
|
||||||
const ref = (p.reference || "").trim();
|
const ref = (p.reference || "").trim();
|
||||||
@@ -274,9 +288,11 @@ async function openSaveModal() {
|
|||||||
const label = ref
|
const label = ref
|
||||||
? `${indent}${escHtml(ref)} \u2014 ${escHtml(p.title)}`
|
? `${indent}${escHtml(ref)} \u2014 ${escHtml(p.title)}`
|
||||||
: `${indent}${escHtml(p.title)}`;
|
: `${indent}${escHtml(p.title)}`;
|
||||||
return `<option value="${escAttr(p.id)}">${label}</option>`;
|
const selected = p.id === preselected ? " selected" : "";
|
||||||
|
return `<option value="${escAttr(p.id)}"${selected}>${label}</option>`;
|
||||||
})
|
})
|
||||||
.join("");
|
.join("");
|
||||||
|
if (preselected) sel.value = preselected;
|
||||||
}
|
}
|
||||||
|
|
||||||
const list = document.getElementById("frist-save-list")!;
|
const list = document.getElementById("frist-save-list")!;
|
||||||
@@ -1260,19 +1276,27 @@ function expandCardCalc(card: HTMLElement, autoSelectPill: HTMLElement | null) {
|
|||||||
card.classList.add("is-expanded");
|
card.classList.add("is-expanded");
|
||||||
card.setAttribute("aria-expanded", "true");
|
card.setAttribute("aria-expanded", "true");
|
||||||
|
|
||||||
const panel = buildCalcPanel(cardData, rulePills);
|
// m/paliad#57 part 4: when the user clicked a specific rule pill, the
|
||||||
card.appendChild(panel);
|
// context is already known — the calc panel renders with that pill
|
||||||
|
// locked in and no "Which context?" picker. The card's pill list is
|
||||||
|
// hidden via CSS while is-expanded so the rules aren't listed twice.
|
||||||
|
// When the user clicked the card body (no autoSelectPill), the picker
|
||||||
|
// is the primary surface — still no duplicate pill list above it.
|
||||||
|
const lockedPill = (autoSelectPill && autoSelectPill.dataset.kind === "rule")
|
||||||
|
? rulePills.find((p) =>
|
||||||
|
p.proceeding?.code === autoSelectPill.dataset.proc
|
||||||
|
&& (autoSelectPill.dataset.focus
|
||||||
|
? p.rule_local_code === autoSelectPill.dataset.focus
|
||||||
|
: true))
|
||||||
|
: undefined;
|
||||||
|
|
||||||
// Auto-select the clicked pill if it's a rule pill; otherwise the
|
const panel = buildCalcPanel(cardData, rulePills, lockedPill || null);
|
||||||
// first pill is preselected by buildCalcPanel.
|
card.appendChild(panel);
|
||||||
if (autoSelectPill && autoSelectPill.dataset.kind === "rule") {
|
|
||||||
selectCalcPill(card, autoSelectPill.dataset.proc, autoSelectPill.dataset.focus);
|
|
||||||
}
|
|
||||||
|
|
||||||
scheduleCardCalc(card);
|
scheduleCardCalc(card);
|
||||||
}
|
}
|
||||||
|
|
||||||
function buildCalcPanel(_cardData: SearchCard, rulePills: SearchPill[]): HTMLElement {
|
function buildCalcPanel(_cardData: SearchCard, rulePills: SearchPill[], lockedPill: SearchPill | null = null): HTMLElement {
|
||||||
const panel = document.createElement("div");
|
const panel = document.createElement("div");
|
||||||
panel.className = "fristen-card-calc";
|
panel.className = "fristen-card-calc";
|
||||||
// stopPropagation so clicks inside the panel don't bubble to the
|
// stopPropagation so clicks inside the panel don't bubble to the
|
||||||
@@ -1283,10 +1307,38 @@ function buildCalcPanel(_cardData: SearchCard, rulePills: SearchPill[]): HTMLEle
|
|||||||
const lang = getLang();
|
const lang = getLang();
|
||||||
const today = new Date().toISOString().split("T")[0];
|
const today = new Date().toISOString().split("T")[0];
|
||||||
|
|
||||||
// Pill picker (only when >1 rule pill).
|
// Picker semantics (m/paliad#57 part 4):
|
||||||
const pickerHtml = rulePills.length <= 1
|
// - lockedPill set → context known (user clicked a specific
|
||||||
? `<input type="hidden" class="fristen-card-calc-pill-picker" data-proc="${escAttr(rulePills[0].proceeding?.code || "")}" data-focus="${escAttr(rulePills[0].rule_local_code || "")}" />`
|
// rule pill on the card). Render as a
|
||||||
: `<fieldset class="fristen-card-calc-pill-picker" role="radiogroup">
|
// hidden input only; the calc panel shows
|
||||||
|
// no "Which context?" question. A small
|
||||||
|
// "ändern" link reopens the picker fieldset.
|
||||||
|
// - rulePills.length <= 1 → only one possible context, never a
|
||||||
|
// picker (hidden input carries the data).
|
||||||
|
// - otherwise → show the picker as primary surface; the
|
||||||
|
// card's pill list is hidden via CSS while
|
||||||
|
// the panel is open, so the user isn't
|
||||||
|
// asked the same thing twice.
|
||||||
|
let pickerHtml: string;
|
||||||
|
if (lockedPill) {
|
||||||
|
const procName = lockedPill.proceeding
|
||||||
|
? (lang === "en" && lockedPill.proceeding.name_en ? lockedPill.proceeding.name_en : lockedPill.proceeding.name_de)
|
||||||
|
: "";
|
||||||
|
const ruleName = lang === "en" && lockedPill.rule_name_en ? lockedPill.rule_name_en : lockedPill.rule_name_de;
|
||||||
|
const src = lockedPill.legal_source_display || lockedPill.legal_source || "";
|
||||||
|
const reopenLabel = t("deadlines.card.calc.pill_picker.change");
|
||||||
|
pickerHtml = `<div class="fristen-card-calc-pill-locked">
|
||||||
|
<span class="fristen-card-calc-pill-locked-label">${escHtml(t("deadlines.card.calc.pill_picker.locked_label"))}</span>
|
||||||
|
<span class="fristen-card-calc-pill-locked-proc">${escHtml(procName)}</span>
|
||||||
|
<span class="fristen-card-calc-pill-locked-rule">${escHtml(ruleName)}</span>
|
||||||
|
${src ? `<span class="fristen-card-calc-pill-locked-source">${escHtml(src)}</span>` : ""}
|
||||||
|
${rulePills.length > 1 ? `<button type="button" class="fristen-card-calc-pill-change">${escHtml(reopenLabel)}</button>` : ""}
|
||||||
|
<input type="hidden" class="fristen-card-calc-pill-picker" data-proc="${escAttr(lockedPill.proceeding?.code || "")}" data-focus="${escAttr(lockedPill.rule_local_code || "")}" />
|
||||||
|
</div>`;
|
||||||
|
} else if (rulePills.length <= 1) {
|
||||||
|
pickerHtml = `<input type="hidden" class="fristen-card-calc-pill-picker" data-proc="${escAttr(rulePills[0].proceeding?.code || "")}" data-focus="${escAttr(rulePills[0].rule_local_code || "")}" />`;
|
||||||
|
} else {
|
||||||
|
pickerHtml = `<fieldset class="fristen-card-calc-pill-picker" role="radiogroup">
|
||||||
<legend class="fristen-card-calc-label">${escHtml(t("deadlines.card.calc.pill_picker.label"))}</legend>
|
<legend class="fristen-card-calc-label">${escHtml(t("deadlines.card.calc.pill_picker.label"))}</legend>
|
||||||
${rulePills.map((p, i) => {
|
${rulePills.map((p, i) => {
|
||||||
const procName = p.proceeding ? (lang === "en" && p.proceeding.name_en ? p.proceeding.name_en : p.proceeding.name_de) : "";
|
const procName = p.proceeding ? (lang === "en" && p.proceeding.name_en ? p.proceeding.name_en : p.proceeding.name_de) : "";
|
||||||
@@ -1300,6 +1352,7 @@ function buildCalcPanel(_cardData: SearchCard, rulePills: SearchPill[]): HTMLEle
|
|||||||
</label>`;
|
</label>`;
|
||||||
}).join("")}
|
}).join("")}
|
||||||
</fieldset>`;
|
</fieldset>`;
|
||||||
|
}
|
||||||
|
|
||||||
panel.innerHTML = `
|
panel.innerHTML = `
|
||||||
<button type="button" class="fristen-card-calc-close" aria-label="${escAttr(t("deadlines.card.calc.close"))}">×</button>
|
<button type="button" class="fristen-card-calc-close" aria-label="${escAttr(t("deadlines.card.calc.close"))}">×</button>
|
||||||
@@ -1352,6 +1405,38 @@ function buildCalcPanel(_cardData: SearchCard, rulePills: SearchPill[]): HTMLEle
|
|||||||
void addCalcToProject(card, last);
|
void addCalcToProject(card, last);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
// "ändern" — swap the locked-context caption for the full radio
|
||||||
|
// picker so the user can change context without collapsing the panel.
|
||||||
|
panel.querySelector<HTMLButtonElement>(".fristen-card-calc-pill-change")?.addEventListener("click", () => {
|
||||||
|
const card = panel.closest<HTMLElement>(".fristen-card");
|
||||||
|
const locked = panel.querySelector<HTMLElement>(".fristen-card-calc-pill-locked");
|
||||||
|
if (!card || !locked) return;
|
||||||
|
const fieldset = document.createElement("fieldset");
|
||||||
|
fieldset.className = "fristen-card-calc-pill-picker";
|
||||||
|
fieldset.setAttribute("role", "radiogroup");
|
||||||
|
const lockedProc = locked.querySelector<HTMLInputElement>("input.fristen-card-calc-pill-picker")?.dataset.proc || "";
|
||||||
|
const lockedFocus = locked.querySelector<HTMLInputElement>("input.fristen-card-calc-pill-picker")?.dataset.focus || "";
|
||||||
|
fieldset.innerHTML = `
|
||||||
|
<legend class="fristen-card-calc-label">${escHtml(t("deadlines.card.calc.pill_picker.label"))}</legend>
|
||||||
|
${rulePills.map((p, i) => {
|
||||||
|
const procName = p.proceeding ? (lang === "en" && p.proceeding.name_en ? p.proceeding.name_en : p.proceeding.name_de) : "";
|
||||||
|
const ruleName = lang === "en" && p.rule_name_en ? p.rule_name_en : p.rule_name_de;
|
||||||
|
const src = p.legal_source_display || p.legal_source || "";
|
||||||
|
const isChecked = (p.proceeding?.code || "") === lockedProc
|
||||||
|
&& (p.rule_local_code || "") === lockedFocus;
|
||||||
|
return `<label class="fristen-card-calc-pill-option">
|
||||||
|
<input type="radio" name="fristen-card-calc-pill" value="${i}" ${isChecked ? "checked" : ""} data-proc="${escAttr(p.proceeding?.code || "")}" data-focus="${escAttr(p.rule_local_code || "")}" />
|
||||||
|
<span class="fristen-card-calc-pill-option-proc">${escHtml(procName)}</span>
|
||||||
|
<span class="fristen-card-calc-pill-option-rule">${escHtml(ruleName)}</span>
|
||||||
|
${src ? `<span class="fristen-card-calc-pill-option-source">${escHtml(src)}</span>` : ""}
|
||||||
|
</label>`;
|
||||||
|
}).join("")}`;
|
||||||
|
locked.replaceWith(fieldset);
|
||||||
|
fieldset.querySelectorAll<HTMLInputElement>('input[name="fristen-card-calc-pill"]').forEach((r) => {
|
||||||
|
r.addEventListener("change", () => scheduleCardCalc(card, 0));
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
return panel;
|
return panel;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1555,6 +1640,7 @@ async function addCalcToProject(card: HTMLElement, calc: RuleCalcResponse) {
|
|||||||
const lang = getLang();
|
const lang = getLang();
|
||||||
const ruleName = lang === "en" ? calc.rule.nameEN : calc.rule.nameDE;
|
const ruleName = lang === "en" ? calc.rule.nameEN : calc.rule.nameDE;
|
||||||
const dueLabel = formatDate(calc.dueDate);
|
const dueLabel = formatDate(calc.dueDate);
|
||||||
|
const preselected = preselectedProjectId();
|
||||||
msgEl.innerHTML = `
|
msgEl.innerHTML = `
|
||||||
<div class="fristen-card-calc-add-picker">
|
<div class="fristen-card-calc-add-picker">
|
||||||
<label class="fristen-card-calc-label">${escHtml(t("deadlines.save.modal.akte"))}
|
<label class="fristen-card-calc-label">${escHtml(t("deadlines.save.modal.akte"))}
|
||||||
@@ -1563,7 +1649,8 @@ async function addCalcToProject(card: HTMLElement, calc: RuleCalcResponse) {
|
|||||||
const ref = (p.reference || "").trim();
|
const ref = (p.reference || "").trim();
|
||||||
const indent = projectIndent(p.path);
|
const indent = projectIndent(p.path);
|
||||||
const label = ref ? `${indent}${ref} — ${p.title}` : `${indent}${p.title}`;
|
const label = ref ? `${indent}${ref} — ${p.title}` : `${indent}${p.title}`;
|
||||||
return `<option value="${escAttr(p.id)}">${escHtml(label)}</option>`;
|
const selected = p.id === preselected ? " selected" : "";
|
||||||
|
return `<option value="${escAttr(p.id)}"${selected}>${escHtml(label)}</option>`;
|
||||||
}).join("")}
|
}).join("")}
|
||||||
</select>
|
</select>
|
||||||
</label>
|
</label>
|
||||||
@@ -1573,6 +1660,7 @@ async function addCalcToProject(card: HTMLElement, calc: RuleCalcResponse) {
|
|||||||
`;
|
`;
|
||||||
|
|
||||||
const sel = msgEl.querySelector<HTMLSelectElement>(".fristen-card-calc-add-select")!;
|
const sel = msgEl.querySelector<HTMLSelectElement>(".fristen-card-calc-add-select")!;
|
||||||
|
if (preselected) sel.value = preselected;
|
||||||
msgEl.querySelector<HTMLButtonElement>(".fristen-card-calc-add-cancel")!.addEventListener("click", () => {
|
msgEl.querySelector<HTMLButtonElement>(".fristen-card-calc-add-cancel")!.addEventListener("click", () => {
|
||||||
msgEl.innerHTML = "";
|
msgEl.innerHTML = "";
|
||||||
addBtn.disabled = false;
|
addBtn.disabled = false;
|
||||||
@@ -1642,12 +1730,12 @@ function renderConceptCard(card: SearchCard, lang: "de" | "en"): string {
|
|||||||
const triggerPills = card.pills.filter((p) => p.kind === "trigger");
|
const triggerPills = card.pills.filter((p) => p.kind === "trigger");
|
||||||
|
|
||||||
const ruleSection = rulePills.length === 0 ? "" : `
|
const ruleSection = rulePills.length === 0 ? "" : `
|
||||||
<div class="fristen-card-pills-section">
|
<div class="fristen-card-pills-section fristen-card-pills-section--rules">
|
||||||
<h4 class="fristen-card-pills-heading">${escHtml(t("deadlines.search.pills.heading"))}</h4>
|
<h4 class="fristen-card-pills-heading">${escHtml(t("deadlines.search.pills.heading"))}</h4>
|
||||||
<div class="fristen-card-pills">${rulePills.map((p) => renderPill(p, lang)).join("")}</div>
|
<div class="fristen-card-pills">${rulePills.map((p) => renderPill(p, lang)).join("")}</div>
|
||||||
</div>`;
|
</div>`;
|
||||||
const triggerSection = triggerPills.length === 0 ? "" : `
|
const triggerSection = triggerPills.length === 0 ? "" : `
|
||||||
<div class="fristen-card-pills-section">
|
<div class="fristen-card-pills-section fristen-card-pills-section--cross">
|
||||||
<h4 class="fristen-card-pills-heading">${escHtml(t("deadlines.search.pills.cross_cutting"))}</h4>
|
<h4 class="fristen-card-pills-heading">${escHtml(t("deadlines.search.pills.cross_cutting"))}</h4>
|
||||||
<div class="fristen-card-pills">${triggerPills.map((p) => renderPill(p, lang)).join("")}</div>
|
<div class="fristen-card-pills">${triggerPills.map((p) => renderPill(p, lang)).join("")}</div>
|
||||||
</div>`;
|
</div>`;
|
||||||
@@ -2423,6 +2511,17 @@ interface EventCategoryNode {
|
|||||||
let eventCategoryTree: EventCategoryNode[] | null = null;
|
let eventCategoryTree: EventCategoryNode[] | null = null;
|
||||||
let eventCategoryFetchInflight: Promise<EventCategoryNode[]> | null = null;
|
let eventCategoryFetchInflight: Promise<EventCategoryNode[]> | null = null;
|
||||||
|
|
||||||
|
// Top-level cascade roots that represent forward-looking workflows ("I
|
||||||
|
// want to file X, what deadlines does my action trigger?") rather than
|
||||||
|
// the backward-looking calc the Fristenrechner is built for ("event Y
|
||||||
|
// happened, what deadlines spawn?"). m's 2026-05-20 ask (m/paliad#57):
|
||||||
|
// remove these from the "Was ist passiert?" picker — they belong in a
|
||||||
|
// future forward-workflow tool, not here. The DB rows stay so that
|
||||||
|
// future tool can pick them back up; we just hide them at the UI layer.
|
||||||
|
const HIDDEN_CASCADE_ROOTS: ReadonlySet<string> = new Set([
|
||||||
|
"ich-moechte-einreichen",
|
||||||
|
]);
|
||||||
|
|
||||||
async function loadEventCategoryTree(): Promise<EventCategoryNode[]> {
|
async function loadEventCategoryTree(): Promise<EventCategoryNode[]> {
|
||||||
if (eventCategoryTree) return eventCategoryTree;
|
if (eventCategoryTree) return eventCategoryTree;
|
||||||
if (eventCategoryFetchInflight) return eventCategoryFetchInflight;
|
if (eventCategoryFetchInflight) return eventCategoryFetchInflight;
|
||||||
@@ -2431,7 +2530,8 @@ async function loadEventCategoryTree(): Promise<EventCategoryNode[]> {
|
|||||||
const r = await fetch("/api/tools/fristenrechner/event-categories");
|
const r = await fetch("/api/tools/fristenrechner/event-categories");
|
||||||
if (!r.ok) throw new Error(`HTTP ${r.status}`);
|
if (!r.ok) throw new Error(`HTTP ${r.status}`);
|
||||||
const data = await r.json();
|
const data = await r.json();
|
||||||
eventCategoryTree = (data.tree || []) as EventCategoryNode[];
|
const raw = (data.tree || []) as EventCategoryNode[];
|
||||||
|
eventCategoryTree = raw.filter((n) => !HIDDEN_CASCADE_ROOTS.has(n.slug));
|
||||||
return eventCategoryTree;
|
return eventCategoryTree;
|
||||||
} finally {
|
} finally {
|
||||||
eventCategoryFetchInflight = null;
|
eventCategoryFetchInflight = null;
|
||||||
|
|||||||
@@ -272,10 +272,10 @@ const translations: Record<Lang, Record<string, string>> = {
|
|||||||
"deadlines.step1.divider.new": "oder eine neue Akte",
|
"deadlines.step1.divider.new": "oder eine neue Akte",
|
||||||
"deadlines.step1.divider.adhoc": "oder ad-hoc, ohne Akte",
|
"deadlines.step1.divider.adhoc": "oder ad-hoc, ohne Akte",
|
||||||
"deadlines.step1.new.cta": "+ Neue Akte anlegen",
|
"deadlines.step1.new.cta": "+ Neue Akte anlegen",
|
||||||
"deadlines.step1.adhoc.upc": "Custom UPC-Verfahren",
|
"deadlines.step1.adhoc.upc": "UPC-Verfahren",
|
||||||
"deadlines.step1.adhoc.de": "Custom DE-Verfahren",
|
"deadlines.step1.adhoc.de": "DE-Verfahren",
|
||||||
"deadlines.step1.adhoc.epa": "Custom EPA-Verfahren",
|
"deadlines.step1.adhoc.epa": "EPA-Verfahren",
|
||||||
"deadlines.step1.adhoc.dpma": "Custom DPMA-Verfahren",
|
"deadlines.step1.adhoc.dpma": "DPMA-Verfahren",
|
||||||
"deadlines.step1.selected": "Akte:",
|
"deadlines.step1.selected": "Akte:",
|
||||||
"deadlines.step1.reselect": "Andere Akte",
|
"deadlines.step1.reselect": "Andere Akte",
|
||||||
"deadlines.step1.summary.adhoc.suffix": "ohne Akte (Erkundung)",
|
"deadlines.step1.summary.adhoc.suffix": "ohne Akte (Erkundung)",
|
||||||
@@ -345,6 +345,8 @@ const translations: Record<Lang, Record<string, string>> = {
|
|||||||
"deadlines.card.calc.expand_hint": "Frist berechnen oder zu Akte hinzufügen",
|
"deadlines.card.calc.expand_hint": "Frist berechnen oder zu Akte hinzufügen",
|
||||||
"deadlines.card.calc.close": "schließen",
|
"deadlines.card.calc.close": "schließen",
|
||||||
"deadlines.card.calc.pill_picker.label": "Welcher Kontext?",
|
"deadlines.card.calc.pill_picker.label": "Welcher Kontext?",
|
||||||
|
"deadlines.card.calc.pill_picker.locked_label": "Kontext:",
|
||||||
|
"deadlines.card.calc.pill_picker.change": "ändern",
|
||||||
"deadlines.card.calc.trigger.label": "Datum des auslösenden Ereignisses",
|
"deadlines.card.calc.trigger.label": "Datum des auslösenden Ereignisses",
|
||||||
"deadlines.card.calc.flags.label": "Bedingungen:",
|
"deadlines.card.calc.flags.label": "Bedingungen:",
|
||||||
"deadlines.card.calc.flag.with_ccr": "Mit Nichtigkeitswiderklage",
|
"deadlines.card.calc.flag.with_ccr": "Mit Nichtigkeitswiderklage",
|
||||||
@@ -2960,10 +2962,10 @@ const translations: Record<Lang, Record<string, string>> = {
|
|||||||
"deadlines.step1.divider.new": "or a new matter",
|
"deadlines.step1.divider.new": "or a new matter",
|
||||||
"deadlines.step1.divider.adhoc": "or ad-hoc, without a matter",
|
"deadlines.step1.divider.adhoc": "or ad-hoc, without a matter",
|
||||||
"deadlines.step1.new.cta": "+ Create new matter",
|
"deadlines.step1.new.cta": "+ Create new matter",
|
||||||
"deadlines.step1.adhoc.upc": "Custom UPC proceeding",
|
"deadlines.step1.adhoc.upc": "UPC proceeding",
|
||||||
"deadlines.step1.adhoc.de": "Custom DE proceeding",
|
"deadlines.step1.adhoc.de": "DE proceeding",
|
||||||
"deadlines.step1.adhoc.epa": "Custom EPA proceeding",
|
"deadlines.step1.adhoc.epa": "EPA proceeding",
|
||||||
"deadlines.step1.adhoc.dpma": "Custom DPMA proceeding",
|
"deadlines.step1.adhoc.dpma": "DPMA proceeding",
|
||||||
"deadlines.step1.selected": "Matter:",
|
"deadlines.step1.selected": "Matter:",
|
||||||
"deadlines.step1.reselect": "Other matter",
|
"deadlines.step1.reselect": "Other matter",
|
||||||
"deadlines.step1.summary.adhoc.suffix": "no matter (exploration)",
|
"deadlines.step1.summary.adhoc.suffix": "no matter (exploration)",
|
||||||
@@ -3040,6 +3042,8 @@ const translations: Record<Lang, Record<string, string>> = {
|
|||||||
"deadlines.card.calc.expand_hint": "Calculate deadline or add to project",
|
"deadlines.card.calc.expand_hint": "Calculate deadline or add to project",
|
||||||
"deadlines.card.calc.close": "close",
|
"deadlines.card.calc.close": "close",
|
||||||
"deadlines.card.calc.pill_picker.label": "Which context?",
|
"deadlines.card.calc.pill_picker.label": "Which context?",
|
||||||
|
"deadlines.card.calc.pill_picker.locked_label": "Context:",
|
||||||
|
"deadlines.card.calc.pill_picker.change": "change",
|
||||||
"deadlines.card.calc.trigger.label": "Date of triggering event",
|
"deadlines.card.calc.trigger.label": "Date of triggering event",
|
||||||
"deadlines.card.calc.flags.label": "Conditions:",
|
"deadlines.card.calc.flags.label": "Conditions:",
|
||||||
"deadlines.card.calc.flag.with_ccr": "With counterclaim for revocation",
|
"deadlines.card.calc.flag.with_ccr": "With counterclaim for revocation",
|
||||||
|
|||||||
@@ -161,19 +161,19 @@ export function renderFristenrechner(): string {
|
|||||||
<div className="fristen-adhoc-chips" role="group" aria-label="Ad-hoc proceeding">
|
<div className="fristen-adhoc-chips" role="group" aria-label="Ad-hoc proceeding">
|
||||||
<button type="button" className="fristen-adhoc-chip" data-ad-hoc="upc"
|
<button type="button" className="fristen-adhoc-chip" data-ad-hoc="upc"
|
||||||
data-i18n="deadlines.step1.adhoc.upc">
|
data-i18n="deadlines.step1.adhoc.upc">
|
||||||
Custom UPC proceeding
|
UPC proceeding
|
||||||
</button>
|
</button>
|
||||||
<button type="button" className="fristen-adhoc-chip" data-ad-hoc="de"
|
<button type="button" className="fristen-adhoc-chip" data-ad-hoc="de"
|
||||||
data-i18n="deadlines.step1.adhoc.de">
|
data-i18n="deadlines.step1.adhoc.de">
|
||||||
Custom DE proceeding
|
DE proceeding
|
||||||
</button>
|
</button>
|
||||||
<button type="button" className="fristen-adhoc-chip" data-ad-hoc="epa"
|
<button type="button" className="fristen-adhoc-chip" data-ad-hoc="epa"
|
||||||
data-i18n="deadlines.step1.adhoc.epa">
|
data-i18n="deadlines.step1.adhoc.epa">
|
||||||
Custom EPA proceeding
|
EPA proceeding
|
||||||
</button>
|
</button>
|
||||||
<button type="button" className="fristen-adhoc-chip" data-ad-hoc="dpma"
|
<button type="button" className="fristen-adhoc-chip" data-ad-hoc="dpma"
|
||||||
data-i18n="deadlines.step1.adhoc.dpma">
|
data-i18n="deadlines.step1.adhoc.dpma">
|
||||||
Custom DPMA proceeding
|
DPMA proceeding
|
||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -971,7 +971,9 @@ export type I18nKey =
|
|||||||
| "deadlines.card.calc.flag.with_cci"
|
| "deadlines.card.calc.flag.with_cci"
|
||||||
| "deadlines.card.calc.flag.with_ccr"
|
| "deadlines.card.calc.flag.with_ccr"
|
||||||
| "deadlines.card.calc.flags.label"
|
| "deadlines.card.calc.flags.label"
|
||||||
|
| "deadlines.card.calc.pill_picker.change"
|
||||||
| "deadlines.card.calc.pill_picker.label"
|
| "deadlines.card.calc.pill_picker.label"
|
||||||
|
| "deadlines.card.calc.pill_picker.locked_label"
|
||||||
| "deadlines.card.calc.result.calculating"
|
| "deadlines.card.calc.result.calculating"
|
||||||
| "deadlines.card.calc.result.court_set"
|
| "deadlines.card.calc.result.court_set"
|
||||||
| "deadlines.card.calc.result.due"
|
| "deadlines.card.calc.result.due"
|
||||||
|
|||||||
@@ -2670,6 +2670,61 @@ input[type="range"]::-moz-range-thumb {
|
|||||||
font-family: ui-monospace, monospace;
|
font-family: ui-monospace, monospace;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* m/paliad#57 part 4 — once a card is expanded into a calc panel,
|
||||||
|
the rule-pill list is redundant with the calc panel's context
|
||||||
|
picker (locked caption or fieldset). Hide it so the user isn't
|
||||||
|
asked the same thing twice. The cross-cutting section stays —
|
||||||
|
those pills are alternative concepts to explore, not the same
|
||||||
|
proceeding context. */
|
||||||
|
.fristen-card.is-expanded .fristen-card-pills-section--rules {
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Locked-context caption when the user clicked a specific rule pill
|
||||||
|
to expand. Shows the picked (proceeding, rule) tuple compactly
|
||||||
|
with a small "ändern" button to swap back to the radio picker. */
|
||||||
|
.fristen-card-calc-pill-locked {
|
||||||
|
display: flex;
|
||||||
|
flex-wrap: wrap;
|
||||||
|
align-items: baseline;
|
||||||
|
gap: 0.4rem;
|
||||||
|
padding: 0.35rem 0.55rem;
|
||||||
|
border: 1px solid var(--color-border-subtle, #ececec);
|
||||||
|
border-radius: 5px;
|
||||||
|
background: rgba(198, 244, 28, 0.06);
|
||||||
|
font-size: 0.88rem;
|
||||||
|
}
|
||||||
|
.fristen-card-calc-pill-locked-label {
|
||||||
|
font-weight: 600;
|
||||||
|
color: var(--color-muted, #777);
|
||||||
|
text-transform: uppercase;
|
||||||
|
font-size: 0.74rem;
|
||||||
|
letter-spacing: 0.04em;
|
||||||
|
}
|
||||||
|
.fristen-card-calc-pill-locked-proc {
|
||||||
|
font-weight: 600;
|
||||||
|
color: var(--color-text, #222);
|
||||||
|
}
|
||||||
|
.fristen-card-calc-pill-locked-rule {
|
||||||
|
color: var(--color-text, #222);
|
||||||
|
}
|
||||||
|
.fristen-card-calc-pill-locked-source {
|
||||||
|
font-size: 0.8rem;
|
||||||
|
color: var(--color-muted, #888);
|
||||||
|
font-family: ui-monospace, monospace;
|
||||||
|
}
|
||||||
|
.fristen-card-calc-pill-change {
|
||||||
|
margin-left: auto;
|
||||||
|
background: transparent;
|
||||||
|
border: 0;
|
||||||
|
padding: 0;
|
||||||
|
color: var(--color-link, #1267a8);
|
||||||
|
cursor: pointer;
|
||||||
|
font-size: 0.82rem;
|
||||||
|
text-decoration: underline;
|
||||||
|
}
|
||||||
|
.fristen-card-calc-pill-change:hover { text-decoration: none; }
|
||||||
|
|
||||||
.fristen-card-calc-inputs {
|
.fristen-card-calc-inputs {
|
||||||
display: flex;
|
display: flex;
|
||||||
flex-wrap: wrap;
|
flex-wrap: wrap;
|
||||||
|
|||||||
Reference in New Issue
Block a user