limpia 2 css con estilos sin usar

main
brobert 1 month ago
parent 138eaa7238
commit 144215a0b5

@ -22,7 +22,9 @@
export let groupName: string | null = null; export let groupName: string | null = null;
export let groupId: string | null = null; export let groupId: string | null = null;
const dispatch = createEventDispatcher<{ changed: { id: number; action: string; patch: any } }>(); const dispatch = createEventDispatcher<{
changed: { id: number; action: string; patch: any };
}>();
const code = display_code ?? id; const code = display_code ?? id;
const codeStr = String(code).padStart(4, "0"); const codeStr = String(code).padStart(4, "0");
@ -74,7 +76,7 @@
function toIsoSqlLocal(d: Date = new Date()): string { function toIsoSqlLocal(d: Date = new Date()): string {
const iso = d.toISOString(); const iso = d.toISOString();
return iso.substring(0, 23).replace('T', ' '); return iso.substring(0, 23).replace("T", " ");
} }
async function doComplete() { async function doComplete() {
@ -85,7 +87,9 @@
const res = await fetch(`/api/tasks/${id}/complete`, { method: "POST" }); const res = await fetch(`/api/tasks/${id}/complete`, { method: "POST" });
if (res.ok) { if (res.ok) {
const data = await res.json().catch(() => null); const data = await res.json().catch(() => null);
const newCompletedAt: string | null = data?.task?.completed_at ? String(data.task.completed_at) : toIsoSqlLocal(new Date()); const newCompletedAt: string | null = data?.task?.completed_at
? String(data.task.completed_at)
: toIsoSqlLocal(new Date());
// Si no tenía responsables, el backend te auto-asigna: reflejarlo localmente // Si no tenía responsables, el backend te auto-asigna: reflejarlo localmente
if (hadNoAssignees && currentUserId) { if (hadNoAssignees && currentUserId) {
const set = new Set<string>(assignees || []); const set = new Set<string>(assignees || []);
@ -94,8 +98,16 @@
} }
completed = true; completed = true;
completed_at = newCompletedAt; completed_at = newCompletedAt;
success(hadNoAssignees ? "Te has asignado y completado la tarea" : "Tarea completada"); success(
dispatch("changed", { id, action: "complete", patch: { completed: true, completed_at, assignees } }); hadNoAssignees
? "Te has asignado y completado la tarea"
: "Tarea completada",
);
dispatch("changed", {
id,
action: "complete",
patch: { completed: true, completed_at, assignees },
});
} else { } else {
const txt = await res.text(); const txt = await res.text();
toastError(txt || "No se pudo completar la tarea"); toastError(txt || "No se pudo completar la tarea");
@ -111,13 +123,19 @@
if (busy || !completed) return; if (busy || !completed) return;
busy = true; busy = true;
try { try {
const res = await fetch(`/api/tasks/${id}/uncomplete`, { method: "POST" }); const res = await fetch(`/api/tasks/${id}/uncomplete`, {
method: "POST",
});
if (res.ok) { if (res.ok) {
await res.json().catch(() => null); await res.json().catch(() => null);
completed = false; completed = false;
completed_at = null; completed_at = null;
success("Tarea reabierta"); success("Tarea reabierta");
dispatch("changed", { id, action: "uncomplete", patch: { completed: false, completed_at: null } }); dispatch("changed", {
id,
action: "uncomplete",
patch: { completed: false, completed_at: null },
});
} else { } else {
const txt = await res.text(); const txt = await res.text();
toastError(txt || "No se pudo deshacer completar"); toastError(txt || "No se pudo deshacer completar");
@ -136,7 +154,10 @@
const res = await fetch(`/api/tasks/${id}/unassign`, { method: "POST" }); const res = await fetch(`/api/tasks/${id}/unassign`, { method: "POST" });
if (res.ok) { if (res.ok) {
if (currentUserId) { if (currentUserId) {
const after = (assignees || []).filter((a) => normalizeDigits(a) !== normalizeDigits(String(currentUserId))); const after = (assignees || []).filter(
(a) =>
normalizeDigits(a) !== normalizeDigits(String(currentUserId)),
);
assignees = after; assignees = after;
} }
success("Asignación eliminada"); success("Asignación eliminada");
@ -198,10 +219,10 @@
} }
} }
async function saveText(text?: string) { async function saveText(text?: string) {
if (busy) return; if (busy) return;
const rawSource = typeof text === "string" ? text : (taskText?.getCurrentText?.() ?? ""); const rawSource =
typeof text === "string" ? text : (taskText?.getCurrentText?.() ?? "");
const raw = String(rawSource).replace(/\s+/g, " ").trim(); const raw = String(rawSource).replace(/\s+/g, " ").trim();
if (raw.length < 1 || raw.length > 1000) { if (raw.length < 1 || raw.length > 1000) {
toastError("La descripción debe tener entre 1 y 1000 caracteres."); toastError("La descripción debe tener entre 1 y 1000 caracteres.");
@ -221,7 +242,11 @@
if (res.ok) { if (res.ok) {
description = raw; description = raw;
success("Descripción actualizada"); success("Descripción actualizada");
dispatch("changed", { id, action: "update_desc", patch: { description } }); dispatch("changed", {
id,
action: "update_desc",
patch: { description },
});
editingText = false; editingText = false;
} else { } else {
const txt = await res.text(); const txt = await res.text();
@ -239,16 +264,22 @@
} }
</script> </script>
<li class="task" class:completed in:fade={{ duration: 180 }} out:fade={{ duration: 180 }}> <li
class="task"
class:completed
in:fade={{ duration: 180 }}
out:fade={{ duration: 180 }}
>
<div class="code">{codeStr}</div> <div class="code">{codeStr}</div>
<TaskText <TaskText
description={description} {description}
{completed} {completed}
editing={editingText} editing={editingText}
{busy} {busy}
bind:this={taskText} bind:this={taskText}
on:toggleEdit={toggleEditText} on:toggleEdit={toggleEditText}
on:saveText={(e) => saveText((e as CustomEvent<{ text: string }>).detail.text)} on:saveText={(e) =>
saveText((e as CustomEvent<{ text: string }>).detail.text)}
on:cancelText={cancelText} on:cancelText={cancelText}
/> />
@ -272,16 +303,17 @@
{canUnassign} {canUnassign}
{busy} {busy}
{completed} {completed}
editingText={editingText} {editingText}
editingDate={editing} editingDate={editing}
dateValue={dateValue} {dateValue}
on:claim={doClaim} on:claim={doClaim}
on:unassign={doUnassign} on:unassign={doUnassign}
on:toggleEditText={toggleEditText} on:toggleEditText={toggleEditText}
on:saveText={saveText} on:saveText={saveText}
on:cancelText={cancelText} on:cancelText={cancelText}
on:toggleEditDate={toggleEdit} on:toggleEditDate={toggleEdit}
on:saveDate={(e) => saveDate((e as CustomEvent<{ value: string | null }>).detail.value)} on:saveDate={(e) =>
saveDate((e as CustomEvent<{ value: string | null }>).detail.value)}
on:clearDate={clearDate} on:clearDate={clearDate}
on:cancelDate={() => (editing = false)} on:cancelDate={() => (editing = false)}
/> />
@ -324,9 +356,6 @@
gap: 6px; gap: 6px;
align-items: center; align-items: center;
} }
.muted {
color: var(--color-text-muted);
}
.assignees-container { .assignees-container {
grid-row: 4/5; grid-row: 4/5;
grid-column: 1/2; grid-column: 1/2;
@ -350,69 +379,21 @@
align-items: center; align-items: center;
justify-content: flex-end; justify-content: flex-end;
} }
.btn {
padding: 4px 8px;
border: 1px solid var(--color-border);
background: var(--color-surface);
color: var(--color-text);
border-radius: 6px;
font-size: 13px;
cursor: pointer;
font-family: monospace;
box-shadow: 0 0 8px 4px var(--color-border);
margin-bottom: 4px;
}
.btn[disabled] {
opacity: 0.6;
cursor: not-allowed;
}
.btn.primary {
border-color: var(--color-primary);
background: var(--color-primary-muted);
color: var(--color-text);
}
:global(.task .btn.primary svg) { :global(.task .btn.primary svg) {
margin-right: 8px; margin-right: 8px;
} }
.btn.ghost {
background: transparent;
}
.btn.danger {
background: var(--color-danger);
color: #fff;
border-color: transparent;
}
.icon-btn {
border: 1px solid var(--color-surface);
border-radius: 6px;
background: var(--color-surface);
font-size: 12px;
line-height: 1;
font-family: monospace;
box-shadow: 0 0 8px 4px var(--color-border);
}
:global(.task .icon-btn svg) { :global(.task .icon-btn svg) {
margin-right: 8px; margin-right: 8px;
} }
.date {
padding: 4px 6px;
font-size: 14px;
}
@media (max-width: 768px) { @media (max-width: 768px) {
.actions { .actions {
justify-self: stretch; justify-self: stretch;
} }
.actions .secondary-action {
flex: 0 0 auto;
}
/* Botón de completar a ancho completo en mobile */ /* Botón de completar a ancho completo en mobile */
.complete { .complete {
grid-column: 1/3; grid-column: 1/3;
justify-self: stretch; justify-self: stretch;
} }
.complete .btn {
width: 100%;
}
} }
@media (max-width: 480px) { @media (max-width: 480px) {
.task { .task {
@ -427,16 +408,7 @@
grid-column: 1/3; grid-column: 1/3;
justify-self: flex-end; justify-self: flex-end;
} }
.icon-btn {
padding: 2px 8px;
}
} }
/* Badge de responsables */ /* Badge de responsables */
.icon-btn-svg {
fill-rule: evenodd;
clip-rule: evenodd;
fill: var(--color-text);
}
</style> </style>

@ -328,8 +328,4 @@
padding: 0; padding: 0;
list-style: none; list-style: none;
} }
.footnote {
margin-top: 0.75rem;
color: var(--color-text-muted);
}
</style> </style>

Loading…
Cancel
Save