@consilioweb/payload-support 0.12.0 → 0.13.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.
@@ -71,16 +71,19 @@
71
71
  }
72
72
  }
73
73
 
74
- // detail__title (maquette) : h1 20px/1.3, 600
74
+ // detail__title (maquette) : h1 20px/1.3, 600, text-wrap: pretty
75
+ // Multi-ligne autorisee, on tronque a 2 lignes via line-clamp pour eviter de pousser le header
75
76
  .ticketSubject {
76
77
  font-size: 20px;
77
78
  font-weight: 600;
78
79
  line-height: 1.3;
79
80
  color: var(--theme-text);
80
81
  margin: 0;
82
+ text-wrap: pretty;
83
+ display: -webkit-box;
84
+ -webkit-line-clamp: 2;
85
+ -webkit-box-orient: vertical;
81
86
  overflow: hidden;
82
- text-overflow: ellipsis;
83
- white-space: nowrap;
84
87
  }
85
88
 
86
89
  .topBarRight {
@@ -198,12 +201,12 @@
198
201
  align-items: center;
199
202
  }
200
203
 
201
- // dl/dt/dd (kv maquette) — grid 100px 1fr, gap 8px/12px
204
+ // dl/dt/dd (kv maquette) — grid 100px 1fr, label aligné gauche, value étirée
202
205
  .sideField {
203
- display: flex;
204
- justify-content: space-between;
206
+ display: grid;
207
+ grid-template-columns: 100px 1fr;
205
208
  align-items: center;
206
- gap: 8px;
209
+ gap: 8px 12px;
207
210
  padding: 4px 0;
208
211
  font-size: 13px;
209
212
  line-height: 1.5;
@@ -219,11 +222,14 @@
219
222
  display: flex;
220
223
  align-items: center;
221
224
  gap: 8px;
225
+ min-width: 0;
222
226
  }
223
227
 
224
228
  // Inline select for sidebar editable fields (kv__edit maquette)
229
+ // Left-aligned dans la grid (la valeur s'aligne au début de la colonne 2)
225
230
  .sideSelect {
226
231
  padding: 2px 8px;
232
+ margin: -2px -8px -2px 0;
227
233
  border-radius: 4px;
228
234
  border: 1px solid transparent;
229
235
  background: transparent;
@@ -232,8 +238,10 @@
232
238
  color: var(--theme-text);
233
239
  cursor: pointer;
234
240
  transition: background 80ms ease;
235
- text-align: right;
236
- max-width: 160px;
241
+ text-align: left;
242
+ max-width: 100%;
243
+ width: 100%;
244
+ justify-self: start;
237
245
 
238
246
  &:hover { background: var(--theme-elevation-100); }
239
247
  &:focus {
@@ -687,6 +695,18 @@
687
695
  cursor: pointer;
688
696
  font-weight: 500;
689
697
  user-select: none;
698
+ transition: color 120ms ease;
699
+ }
700
+
701
+ // Note interne (1er label) : warning quand cochee
702
+ // Notifier (2e label) : info quand cochee
703
+ // Approximation via :has() — supportee Chrome/Safari/FF >= 121
704
+ > label:nth-of-type(1):has(input:checked) {
705
+ color: var(--theme-warning-500, #c97a0a);
706
+ input[type="checkbox"]:checked { background: var(--theme-warning-500, #c97a0a); }
707
+ }
708
+ > label:nth-of-type(2):has(input:checked) {
709
+ color: var(--theme-info-500, #2a6bd8);
690
710
  }
691
711
 
692
712
  // Toggle switch (toggle__sw maquette) : 28×16, info-500 quand checked
@@ -838,23 +858,49 @@
838
858
  &.timerActive { color: var(--theme-error-500, #c4392c); }
839
859
  }
840
860
 
841
- // Bouton Go / Pause / Save : 30px height, micro typo 600
861
+ // Bouton Go / Pause / Save (tt__go maquette) :
862
+ // - "paused" (Go) : bg theme-text, color theme-bg (carré sombre, contrasté)
863
+ // - "running" (Pause) : bg error-500, color white (stop visible)
864
+ // - "save" (💾) : ghost neutre theme-bg + border elevation-200
865
+ // Approximation : on neutralise par défaut, et les classes appellantes appliquent le style.
842
866
  .timerBtn {
843
867
  display: inline-flex;
844
868
  align-items: center;
869
+ justify-content: center;
845
870
  gap: 6px;
846
871
  height: 30px;
847
872
  padding: 0 12px;
848
873
  border-radius: 4px;
849
- border: 1px solid var(--theme-elevation-200, var(--theme-input-border));
850
- background: var(--theme-bg);
874
+ border: 1px solid var(--theme-text);
875
+ background: var(--theme-text);
876
+ color: var(--theme-bg, #fff);
851
877
  font-size: 12px;
852
- font-weight: 500;
853
- line-height: 1;
854
- color: var(--theme-text);
878
+ font-weight: 600;
855
879
  cursor: pointer;
856
- transition: background 80ms ease;
857
- &:hover { background: var(--theme-elevation-100); }
880
+ transition: background 80ms ease, border-color 80ms ease;
881
+ white-space: nowrap;
882
+ &:hover { background: var(--theme-elevation-800); border-color: var(--theme-elevation-800); }
883
+ &:disabled { opacity: 0.5; cursor: not-allowed; }
884
+ }
885
+
886
+ // Variante running (tt__go--running maquette) : bg error-500 quand le timer tourne
887
+ .timerBtnRunning {
888
+ background: var(--theme-error-500, #c4392c);
889
+ border-color: var(--theme-error-500, #c4392c);
890
+ color: #fff;
891
+ &:hover {
892
+ background: color-mix(in srgb, var(--theme-error-500, #c4392c) 85%, black);
893
+ border-color: color-mix(in srgb, var(--theme-error-500, #c4392c) 85%, black);
894
+ }
895
+ }
896
+
897
+ // Variante "ghost" pour les boutons secondaires (Save / + Ajouter) : neutre, evite le carre noir partout
898
+ .timerBtnGhost {
899
+ background: var(--theme-bg);
900
+ border-color: var(--theme-elevation-200, var(--theme-input-border));
901
+ color: var(--theme-text);
902
+ font-weight: 500;
903
+ &:hover { background: var(--theme-elevation-100); border-color: var(--theme-elevation-200, var(--theme-input-border)); }
858
904
  }
859
905
 
860
906
  // Activity in sidebar
@@ -1257,8 +1257,8 @@ ${uploadedLinks.join("\n")}` : replyBody.trim() || "[Contenu enrichi]";
1257
1257
  ":",
1258
1258
  String(timerSeconds % 60).padStart(2, "0")
1259
1259
  ] }),
1260
- !timerRunning ? /* @__PURE__ */ jsxRuntime.jsx("button", { className: s__default.default.timerBtn, onClick: () => setTimerRunning(true), "aria-label": "D\xE9marrer le timer", children: timerSeconds > 0 ? "\u25B6" : "\u25B6 Go" }) : /* @__PURE__ */ jsxRuntime.jsx("button", { className: s__default.default.timerBtn, onClick: () => setTimerRunning(false), "aria-label": "Mettre en pause le timer", children: "\u23F8 Pause" }),
1261
- timerSeconds >= 60 && !timerRunning && /* @__PURE__ */ jsxRuntime.jsxs("button", { className: s__default.default.timerBtn, onClick: () => {
1260
+ !timerRunning ? /* @__PURE__ */ jsxRuntime.jsx("button", { className: s__default.default.timerBtn, onClick: () => setTimerRunning(true), "aria-label": "D\xE9marrer le timer", children: timerSeconds > 0 ? "\u25B6" : "\u25B6 Go" }) : /* @__PURE__ */ jsxRuntime.jsx("button", { className: `${s__default.default.timerBtn} ${s__default.default.timerBtnRunning}`, onClick: () => setTimerRunning(false), "aria-label": "Mettre en pause le timer", children: "\u23F8 Pause" }),
1261
+ timerSeconds >= 60 && !timerRunning && /* @__PURE__ */ jsxRuntime.jsxs("button", { className: `${s__default.default.timerBtn} ${s__default.default.timerBtnGhost}`, onClick: () => {
1262
1262
  handleTimerSave();
1263
1263
  localStorage.removeItem(`timer-sec-${ticketId}`);
1264
1264
  localStorage.removeItem(`timer-run-${ticketId}`);
@@ -1271,7 +1271,7 @@ ${uploadedLinks.join("\n")}` : replyBody.trim() || "[Contenu enrichi]";
1271
1271
  /* @__PURE__ */ jsxRuntime.jsx("div", { className: s__default.default.timerBar, "aria-hidden": true, children: /* @__PURE__ */ jsxRuntime.jsx("div", { className: s__default.default.timerBarFill, style: { width: `${Math.min(100, (totalMin + Math.floor(timerSeconds / 60)) / 120 * 100)}%` } }) }),
1272
1272
  /* @__PURE__ */ jsxRuntime.jsxs("div", { style: { display: "flex", gap: 6, marginTop: 8, alignItems: "center" }, children: [
1273
1273
  /* @__PURE__ */ jsxRuntime.jsx("input", { type: "number", min: "1", placeholder: "min", style: { width: 60, padding: "4px 8px", borderRadius: 6, border: "1px solid var(--theme-elevation-200)", fontSize: 12, color: "var(--theme-text)", background: "var(--theme-elevation-0)" }, id: "manual-time-input" }),
1274
- /* @__PURE__ */ jsxRuntime.jsx("button", { className: s__default.default.timerBtn, onClick: async () => {
1274
+ /* @__PURE__ */ jsxRuntime.jsx("button", { className: `${s__default.default.timerBtn} ${s__default.default.timerBtnGhost}`, onClick: async () => {
1275
1275
  const input = document.getElementById("manual-time-input");
1276
1276
  const mins = Number(input?.value);
1277
1277
  if (!mins || mins < 1 || !ticketId) return;
@@ -1250,8 +1250,8 @@ ${uploadedLinks.join("\n")}` : replyBody.trim() || "[Contenu enrichi]";
1250
1250
  ":",
1251
1251
  String(timerSeconds % 60).padStart(2, "0")
1252
1252
  ] }),
1253
- !timerRunning ? /* @__PURE__ */ jsx("button", { className: s.timerBtn, onClick: () => setTimerRunning(true), "aria-label": "D\xE9marrer le timer", children: timerSeconds > 0 ? "\u25B6" : "\u25B6 Go" }) : /* @__PURE__ */ jsx("button", { className: s.timerBtn, onClick: () => setTimerRunning(false), "aria-label": "Mettre en pause le timer", children: "\u23F8 Pause" }),
1254
- timerSeconds >= 60 && !timerRunning && /* @__PURE__ */ jsxs("button", { className: s.timerBtn, onClick: () => {
1253
+ !timerRunning ? /* @__PURE__ */ jsx("button", { className: s.timerBtn, onClick: () => setTimerRunning(true), "aria-label": "D\xE9marrer le timer", children: timerSeconds > 0 ? "\u25B6" : "\u25B6 Go" }) : /* @__PURE__ */ jsx("button", { className: `${s.timerBtn} ${s.timerBtnRunning}`, onClick: () => setTimerRunning(false), "aria-label": "Mettre en pause le timer", children: "\u23F8 Pause" }),
1254
+ timerSeconds >= 60 && !timerRunning && /* @__PURE__ */ jsxs("button", { className: `${s.timerBtn} ${s.timerBtnGhost}`, onClick: () => {
1255
1255
  handleTimerSave();
1256
1256
  localStorage.removeItem(`timer-sec-${ticketId}`);
1257
1257
  localStorage.removeItem(`timer-run-${ticketId}`);
@@ -1264,7 +1264,7 @@ ${uploadedLinks.join("\n")}` : replyBody.trim() || "[Contenu enrichi]";
1264
1264
  /* @__PURE__ */ jsx("div", { className: s.timerBar, "aria-hidden": true, children: /* @__PURE__ */ jsx("div", { className: s.timerBarFill, style: { width: `${Math.min(100, (totalMin + Math.floor(timerSeconds / 60)) / 120 * 100)}%` } }) }),
1265
1265
  /* @__PURE__ */ jsxs("div", { style: { display: "flex", gap: 6, marginTop: 8, alignItems: "center" }, children: [
1266
1266
  /* @__PURE__ */ jsx("input", { type: "number", min: "1", placeholder: "min", style: { width: 60, padding: "4px 8px", borderRadius: 6, border: "1px solid var(--theme-elevation-200)", fontSize: 12, color: "var(--theme-text)", background: "var(--theme-elevation-0)" }, id: "manual-time-input" }),
1267
- /* @__PURE__ */ jsx("button", { className: s.timerBtn, onClick: async () => {
1267
+ /* @__PURE__ */ jsx("button", { className: `${s.timerBtn} ${s.timerBtnGhost}`, onClick: async () => {
1268
1268
  const input = document.getElementById("manual-time-input");
1269
1269
  const mins = Number(input?.value);
1270
1270
  if (!mins || mins < 1 || !ticketId) return;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@consilioweb/payload-support",
3
- "version": "0.12.0",
3
+ "version": "0.13.0",
4
4
  "description": "Payload CMS plugin — professional support & ticketing system with AI, SLA, time tracking, live chat, and more",
5
5
  "type": "module",
6
6
  "main": "./dist/index.cjs",
@@ -71,16 +71,19 @@
71
71
  }
72
72
  }
73
73
 
74
- // detail__title (maquette) : h1 20px/1.3, 600
74
+ // detail__title (maquette) : h1 20px/1.3, 600, text-wrap: pretty
75
+ // Multi-ligne autorisee, on tronque a 2 lignes via line-clamp pour eviter de pousser le header
75
76
  .ticketSubject {
76
77
  font-size: 20px;
77
78
  font-weight: 600;
78
79
  line-height: 1.3;
79
80
  color: var(--theme-text);
80
81
  margin: 0;
82
+ text-wrap: pretty;
83
+ display: -webkit-box;
84
+ -webkit-line-clamp: 2;
85
+ -webkit-box-orient: vertical;
81
86
  overflow: hidden;
82
- text-overflow: ellipsis;
83
- white-space: nowrap;
84
87
  }
85
88
 
86
89
  .topBarRight {
@@ -198,12 +201,12 @@
198
201
  align-items: center;
199
202
  }
200
203
 
201
- // dl/dt/dd (kv maquette) — grid 100px 1fr, gap 8px/12px
204
+ // dl/dt/dd (kv maquette) — grid 100px 1fr, label aligné gauche, value étirée
202
205
  .sideField {
203
- display: flex;
204
- justify-content: space-between;
206
+ display: grid;
207
+ grid-template-columns: 100px 1fr;
205
208
  align-items: center;
206
- gap: 8px;
209
+ gap: 8px 12px;
207
210
  padding: 4px 0;
208
211
  font-size: 13px;
209
212
  line-height: 1.5;
@@ -219,11 +222,14 @@
219
222
  display: flex;
220
223
  align-items: center;
221
224
  gap: 8px;
225
+ min-width: 0;
222
226
  }
223
227
 
224
228
  // Inline select for sidebar editable fields (kv__edit maquette)
229
+ // Left-aligned dans la grid (la valeur s'aligne au début de la colonne 2)
225
230
  .sideSelect {
226
231
  padding: 2px 8px;
232
+ margin: -2px -8px -2px 0;
227
233
  border-radius: 4px;
228
234
  border: 1px solid transparent;
229
235
  background: transparent;
@@ -232,8 +238,10 @@
232
238
  color: var(--theme-text);
233
239
  cursor: pointer;
234
240
  transition: background 80ms ease;
235
- text-align: right;
236
- max-width: 160px;
241
+ text-align: left;
242
+ max-width: 100%;
243
+ width: 100%;
244
+ justify-self: start;
237
245
 
238
246
  &:hover { background: var(--theme-elevation-100); }
239
247
  &:focus {
@@ -687,6 +695,18 @@
687
695
  cursor: pointer;
688
696
  font-weight: 500;
689
697
  user-select: none;
698
+ transition: color 120ms ease;
699
+ }
700
+
701
+ // Note interne (1er label) : warning quand cochee
702
+ // Notifier (2e label) : info quand cochee
703
+ // Approximation via :has() — supportee Chrome/Safari/FF >= 121
704
+ > label:nth-of-type(1):has(input:checked) {
705
+ color: var(--theme-warning-500, #c97a0a);
706
+ input[type="checkbox"]:checked { background: var(--theme-warning-500, #c97a0a); }
707
+ }
708
+ > label:nth-of-type(2):has(input:checked) {
709
+ color: var(--theme-info-500, #2a6bd8);
690
710
  }
691
711
 
692
712
  // Toggle switch (toggle__sw maquette) : 28×16, info-500 quand checked
@@ -838,23 +858,49 @@
838
858
  &.timerActive { color: var(--theme-error-500, #c4392c); }
839
859
  }
840
860
 
841
- // Bouton Go / Pause / Save : 30px height, micro typo 600
861
+ // Bouton Go / Pause / Save (tt__go maquette) :
862
+ // - "paused" (Go) : bg theme-text, color theme-bg (carré sombre, contrasté)
863
+ // - "running" (Pause) : bg error-500, color white (stop visible)
864
+ // - "save" (💾) : ghost neutre theme-bg + border elevation-200
865
+ // Approximation : on neutralise par défaut, et les classes appellantes appliquent le style.
842
866
  .timerBtn {
843
867
  display: inline-flex;
844
868
  align-items: center;
869
+ justify-content: center;
845
870
  gap: 6px;
846
871
  height: 30px;
847
872
  padding: 0 12px;
848
873
  border-radius: 4px;
849
- border: 1px solid var(--theme-elevation-200, var(--theme-input-border));
850
- background: var(--theme-bg);
874
+ border: 1px solid var(--theme-text);
875
+ background: var(--theme-text);
876
+ color: var(--theme-bg, #fff);
851
877
  font-size: 12px;
852
- font-weight: 500;
853
- line-height: 1;
854
- color: var(--theme-text);
878
+ font-weight: 600;
855
879
  cursor: pointer;
856
- transition: background 80ms ease;
857
- &:hover { background: var(--theme-elevation-100); }
880
+ transition: background 80ms ease, border-color 80ms ease;
881
+ white-space: nowrap;
882
+ &:hover { background: var(--theme-elevation-800); border-color: var(--theme-elevation-800); }
883
+ &:disabled { opacity: 0.5; cursor: not-allowed; }
884
+ }
885
+
886
+ // Variante running (tt__go--running maquette) : bg error-500 quand le timer tourne
887
+ .timerBtnRunning {
888
+ background: var(--theme-error-500, #c4392c);
889
+ border-color: var(--theme-error-500, #c4392c);
890
+ color: #fff;
891
+ &:hover {
892
+ background: color-mix(in srgb, var(--theme-error-500, #c4392c) 85%, black);
893
+ border-color: color-mix(in srgb, var(--theme-error-500, #c4392c) 85%, black);
894
+ }
895
+ }
896
+
897
+ // Variante "ghost" pour les boutons secondaires (Save / + Ajouter) : neutre, evite le carre noir partout
898
+ .timerBtnGhost {
899
+ background: var(--theme-bg);
900
+ border-color: var(--theme-elevation-200, var(--theme-input-border));
901
+ color: var(--theme-text);
902
+ font-weight: 500;
903
+ &:hover { background: var(--theme-elevation-100); border-color: var(--theme-elevation-200, var(--theme-input-border)); }
858
904
  }
859
905
 
860
906
  // Activity in sidebar
@@ -1202,10 +1202,10 @@ const [clientTyping, setClientTyping] = useState(false)
1202
1202
  {!timerRunning ? (
1203
1203
  <button className={s.timerBtn} onClick={() => setTimerRunning(true)} aria-label="Démarrer le timer">{timerSeconds > 0 ? '▶' : '▶ Go'}</button>
1204
1204
  ) : (
1205
- <button className={s.timerBtn} onClick={() => setTimerRunning(false)} aria-label="Mettre en pause le timer">⏸ Pause</button>
1205
+ <button className={`${s.timerBtn} ${s.timerBtnRunning}`} onClick={() => setTimerRunning(false)} aria-label="Mettre en pause le timer">⏸ Pause</button>
1206
1206
  )}
1207
1207
  {timerSeconds >= 60 && !timerRunning && (
1208
- <button className={s.timerBtn} onClick={() => { handleTimerSave(); localStorage.removeItem(`timer-sec-${ticketId}`); localStorage.removeItem(`timer-run-${ticketId}`) }} aria-label="Sauvegarder le temps">💾 {Math.round(timerSeconds / 60)}m</button>
1208
+ <button className={`${s.timerBtn} ${s.timerBtnGhost}`} onClick={() => { handleTimerSave(); localStorage.removeItem(`timer-sec-${ticketId}`); localStorage.removeItem(`timer-run-${ticketId}`) }} aria-label="Sauvegarder le temps">💾 {Math.round(timerSeconds / 60)}m</button>
1209
1209
  )}
1210
1210
  </div>
1211
1211
  {/* Progress bar (tt__bar maquette) — full = 120 min reference */}
@@ -1215,7 +1215,7 @@ const [clientTyping, setClientTyping] = useState(false)
1215
1215
  {/* Manual time entry */}
1216
1216
  <div style={{ display: 'flex', gap: 6, marginTop: 8, alignItems: 'center' }}>
1217
1217
  <input type="number" min="1" placeholder="min" style={{ width: 60, padding: '4px 8px', borderRadius: 6, border: '1px solid var(--theme-elevation-200)', fontSize: 12, color: 'var(--theme-text)', background: 'var(--theme-elevation-0)' }} id="manual-time-input" />
1218
- <button className={s.timerBtn} onClick={async () => {
1218
+ <button className={`${s.timerBtn} ${s.timerBtnGhost}`} onClick={async () => {
1219
1219
  const input = document.getElementById('manual-time-input') as HTMLInputElement
1220
1220
  const mins = Number(input?.value)
1221
1221
  if (!mins || mins < 1 || !ticketId) return