diff --git a/devboard/client/src/components/Task/TaskModal.jsx b/devboard/client/src/components/Task/TaskModal.jsx index b81cf6e..61372c2 100644 --- a/devboard/client/src/components/Task/TaskModal.jsx +++ b/devboard/client/src/components/Task/TaskModal.jsx @@ -4,6 +4,14 @@ import { useBoard } from "../../context/BoardContext"; import { QRCodeSVG } from "qrcode.react"; const TITLE_MAX_LENGTH = 100; +// The AI generator asks Gemini for "2-3 sentences", which lands around 150 to +// 400 characters. A budget has to hold that plus a note typed afterwards, +// otherwise the field cuts off the text the button just produced. +const DESCRIPTION_MAX_LENGTH = 500; +// Where the counter starts warning. Kept as fractions so both follow the +// budget above instead of drifting when it changes. +const DESCRIPTION_WARN_AT = Math.round(DESCRIPTION_MAX_LENGTH * 0.8); +const DESCRIPTION_ALERT_AT = Math.round(DESCRIPTION_MAX_LENGTH * 0.92); const COPY_SUFFIX = " (copy)"; const COLORS = [ @@ -48,6 +56,14 @@ const TaskModal = ({ t.title?.toLowerCase().trim() === form.title.toLowerCase().trim() && t._id !== task?._id, ); + // Both counters were computed inline before, the word count twice in a row: + // once for the number and once for the plural of "word". + const descriptionLength = form.description.length; + const descriptionWords = form.description + .trim() + .split(/\s+/) + .filter(Boolean).length; + // Tags are stored the way they were typed, so the list keeps the first // spelling it sees and matches case insensitively: typing "rea" should still // find an existing "React" rather than nothing. @@ -349,6 +365,7 @@ const TaskModal = ({