@imenam/mcp-messenger 1.0.18 → 1.0.20

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.
@@ -61,7 +61,7 @@
61
61
  <dialog class="modal" id="purge">
62
62
  <div class="modal-card">
63
63
  <div class="modal-head">
64
- <h2>Purger les boîtes inactives</h2>
64
+ <h2>Nettoyer les boîtes</h2>
65
65
  <button type="button" class="btn btn--icon btn--ghost" id="purge-close" aria-label="Fermer">
66
66
  <svg class="icon" viewBox="0 0 24 24" aria-hidden="true">
67
67
  <path d="M18 6 6 18" />
@@ -70,16 +70,26 @@
70
70
  </button>
71
71
  </div>
72
72
  <p class="modal-sub">
73
- Une boîte est inactive quand plus rien ne l'a touchée depuis la date choisie : ni connexion, ni message reçu
74
- ou envoyé. Une boîte créée après cette date est laissée tranquille, même vide. La suppression est définitive
75
- et emporte les messages que plus personne ne pourrait lire ; ce que le correspondant a reçu de son côté reste
76
- intact.
73
+ Deux nettoyages, deux critères. La suppression est définitive dans les deux cas, et emporte les messages que
74
+ plus personne ne pourrait lire ; ce que le correspondant a reçu de son côté reste intact. Un agent dont toutes
75
+ les boîtes disparaissent quitte l'annuaire avec elles.
77
76
  </p>
78
77
 
78
+ <!-- Premier critère : la boîte n'a jamais servi. Il ne dépend d'aucune date. -->
79
+ <div class="purge-controls">
80
+ <div class="purge-criterion">
81
+ <span class="field-label">Boîtes vides</span>
82
+ <span class="purge-hint">Rien n'y est jamais passé, ni envoi ni réception, quel que soit leur âge.</span>
83
+ </div>
84
+ <button type="button" class="btn" id="purge-preview-empty">Prévisualiser</button>
85
+ </div>
86
+
87
+ <!-- Second critère : la boîte a servi, mais plus rien ne l'a touchée depuis. -->
79
88
  <div class="purge-controls">
80
89
  <label class="field">
81
- <span class="field-label">Sans activité depuis le</span>
90
+ <span class="field-label">Boîtes sans activité depuis le</span>
82
91
  <span class="field-input"><input type="date" id="purge-before" /></span>
92
+ <span class="purge-hint">Ni connexion, ni message. Une boîte créée après cette date est épargnée.</span>
83
93
  </label>
84
94
  <button type="button" class="btn" id="purge-preview">Prévisualiser</button>
85
95
  </div>
@@ -143,6 +153,19 @@
143
153
  <p class="agents-foot muted" id="agents-foot"></p>
144
154
  </aside>
145
155
 
156
+ <!--
157
+ Séparateurs déplaçables. Chacun redimensionne le panneau qu'il borde, à la souris
158
+ comme aux flèches du clavier ; un double-clic rend sa largeur d'origine.
159
+ -->
160
+ <div
161
+ class="resizer"
162
+ id="resize-agents"
163
+ role="separator"
164
+ aria-orientation="vertical"
165
+ aria-label="Largeur de la colonne des agents"
166
+ tabindex="0"
167
+ ></div>
168
+
146
169
  <section class="threads">
147
170
  <div class="threads-head">
148
171
  <h2>Fils</h2>
@@ -156,8 +179,27 @@
156
179
  <ul class="thread-list" id="threads"></ul>
157
180
  </section>
158
181
 
182
+ <div
183
+ class="resizer"
184
+ id="resize-threads"
185
+ role="separator"
186
+ aria-orientation="vertical"
187
+ aria-label="Largeur de la liste des fils"
188
+ tabindex="0"
189
+ ></div>
190
+
159
191
  <section class="reader" id="reader"></section>
160
192
 
193
+ <!-- Suit le volet de détail : il n'existe que lorsque le volet est ouvert. -->
194
+ <div
195
+ class="resizer resizer--sheet"
196
+ id="resize-sheet"
197
+ role="separator"
198
+ aria-orientation="vertical"
199
+ aria-label="Largeur du volet de détail"
200
+ tabindex="0"
201
+ ></div>
202
+
161
203
  <aside class="sheet" id="sheet" hidden></aside>
162
204
  </main>
163
205
 
@@ -335,15 +335,29 @@ body {
335
335
  color: var(--muted);
336
336
  }
337
337
 
338
+ /* Un critère par ligne, son bouton au bout : les deux nettoyages se lisent en parallèle. */
338
339
  .purge-controls {
339
340
  display: flex;
340
341
  align-items: flex-end;
341
342
  gap: 12px;
343
+ padding: 12px 0;
342
344
  }
343
345
 
344
- .purge-controls .field {
346
+ .purge-controls + .purge-controls {
347
+ border-top: 1px solid var(--border-soft);
348
+ }
349
+
350
+ .purge-controls .field,
351
+ .purge-criterion {
345
352
  margin: 0;
346
353
  flex: 1;
354
+ display: grid;
355
+ gap: 4px;
356
+ }
357
+
358
+ .purge-hint {
359
+ font-size: 12px;
360
+ color: var(--muted);
347
361
  }
348
362
 
349
363
  .purge-result {
@@ -532,22 +546,80 @@ body {
532
546
 
533
547
  /* --- Console -------------------------------------------------------------- */
534
548
 
549
+ /*
550
+ Largeurs des panneaux. Ce sont des variables parce qu'elles se déplacent : les
551
+ séparateurs les réécrivent au glissé, et le navigateur les retient d'une visite à
552
+ l'autre. La colonne du lecteur prend ce qui reste, elle n'a donc pas de variable.
553
+ */
535
554
  .console {
555
+ --w-agents: 240px;
556
+ --w-threads: 400px;
557
+ --w-sheet: 360px;
558
+ --w-gutter: 5px;
536
559
  display: grid;
537
- grid-template-columns: 240px 400px minmax(0, 1fr);
560
+ grid-template-columns: var(--w-agents) var(--w-gutter) var(--w-threads) var(--w-gutter) minmax(0, 1fr);
538
561
  height: calc(100vh - var(--topbar-h));
539
562
  }
540
563
 
541
564
  .console.has-sheet {
542
- grid-template-columns: 240px 360px minmax(0, 1fr) 360px;
565
+ grid-template-columns:
566
+ var(--w-agents) var(--w-gutter) var(--w-threads) var(--w-gutter)
567
+ minmax(0, 1fr) var(--w-gutter) var(--w-sheet);
543
568
  }
544
569
 
545
570
  .console.is-collapsed {
546
- grid-template-columns: 57px 360px minmax(0, 1fr);
571
+ grid-template-columns: 57px var(--w-gutter) var(--w-threads) var(--w-gutter) minmax(0, 1fr);
547
572
  }
548
573
 
549
574
  .console.is-collapsed.has-sheet {
550
- grid-template-columns: 57px 360px minmax(0, 1fr) 360px;
575
+ grid-template-columns:
576
+ 57px var(--w-gutter) var(--w-threads) var(--w-gutter)
577
+ minmax(0, 1fr) var(--w-gutter) var(--w-sheet);
578
+ }
579
+
580
+ /* --- Séparateurs déplaçables ---------------------------------------------- */
581
+
582
+ .resizer {
583
+ cursor: col-resize;
584
+ background: none;
585
+ /* La zone saisissable déborde du trait : viser 5 pixels à la souris est pénible. */
586
+ border-left: 4px solid transparent;
587
+ border-right: 4px solid transparent;
588
+ background-clip: padding-box;
589
+ margin: 0 -4px;
590
+ z-index: 1;
591
+ }
592
+
593
+ .resizer:hover,
594
+ .resizer:focus-visible,
595
+ .resizer.is-active {
596
+ background-color: var(--accent);
597
+ background-clip: padding-box;
598
+ outline: none;
599
+ }
600
+
601
+ /* Le volet de détail n'est pas toujours là ; son séparateur non plus. */
602
+ .console:not(.has-sheet) .resizer--sheet {
603
+ display: none;
604
+ }
605
+
606
+ /* Colonne repliée : il n'y a plus de largeur à régler, seulement un rail d'avatars. */
607
+ .console.is-collapsed #resize-agents {
608
+ cursor: default;
609
+ pointer-events: none;
610
+ }
611
+
612
+ /* Pendant le glissé, rien d'autre ne doit réagir : ni sélection de texte, ni survol. */
613
+ .console.is-resizing {
614
+ cursor: col-resize;
615
+ user-select: none;
616
+ }
617
+
618
+ .console.is-resizing .agents,
619
+ .console.is-resizing .threads,
620
+ .console.is-resizing .reader,
621
+ .console.is-resizing .sheet {
622
+ pointer-events: none;
551
623
  }
552
624
 
553
625
  /* --- Colonne des agents --------------------------------------------------- */
@@ -697,6 +769,54 @@ body {
697
769
  padding: 7px 10px;
698
770
  }
699
771
 
772
+ /* La ligne d'une boîte et son bouton de suppression, côte à côte. */
773
+ .box-line {
774
+ display: flex;
775
+ align-items: center;
776
+ gap: 2px;
777
+ }
778
+
779
+ .box-line .box {
780
+ flex: 1;
781
+ min-width: 0;
782
+ }
783
+
784
+ /*
785
+ Le bouton ne se montre qu'au survol ou au clavier : une corbeille par ligne, affichée en
786
+ permanence, transformerait la colonne en champ de mines. Il reste dans le flux — révélé
787
+ par l'opacité et non par `display` — pour que la ligne ne change pas de largeur.
788
+ */
789
+ .box-delete {
790
+ display: flex;
791
+ padding: 5px;
792
+ border: 0;
793
+ border-radius: var(--radius);
794
+ background: none;
795
+ color: var(--muted);
796
+ cursor: pointer;
797
+ opacity: 0;
798
+ }
799
+
800
+ .box-line:hover .box-delete,
801
+ .box-delete:focus-visible {
802
+ opacity: 1;
803
+ }
804
+
805
+ .box-delete:hover {
806
+ background: var(--danger-soft);
807
+ color: var(--danger);
808
+ }
809
+
810
+ .box-delete:focus-visible {
811
+ outline: 2px solid var(--accent);
812
+ outline-offset: -2px;
813
+ }
814
+
815
+ /* Colonne repliée : il n'y a plus de boîtes affichées, donc rien à supprimer. */
816
+ .is-collapsed .box-delete {
817
+ display: none;
818
+ }
819
+
700
820
  .box .agent-name {
701
821
  font-weight: 500;
702
822
  font-size: 13px;
@@ -738,6 +858,19 @@ body {
738
858
  outline-offset: -2px;
739
859
  }
740
860
 
861
+ /* Le même geste un cran plus haut : il se détache donc de la liste des agents. */
862
+ .agents-empty-toggle {
863
+ margin-top: 6px;
864
+ padding-top: 10px;
865
+ border-top: 1px solid var(--border-soft);
866
+ border-radius: 0;
867
+ }
868
+
869
+ /* Colonne repliée : plus de place pour une phrase, et rien à replier de toute façon. */
870
+ .is-collapsed .agents-empty-toggle {
871
+ display: none;
872
+ }
873
+
741
874
  /* Une boîte vide reste lisible mais s'efface : elle est là pour être retrouvée, pas lue. */
742
875
  .box.is-empty .agent-name {
743
876
  color: var(--muted);
@@ -1015,15 +1148,48 @@ body {
1015
1148
  color: var(--accent);
1016
1149
  }
1017
1150
 
1151
+ /* Les pastilles des deux correspondants, puis leurs noms : on voit qui parle avant de lire. */
1018
1152
  .thread-who {
1153
+ display: flex;
1154
+ align-items: center;
1155
+ gap: 8px;
1156
+ margin-top: 4px;
1157
+ min-width: 0;
1158
+ }
1159
+
1160
+ .thread-names {
1019
1161
  font-size: 12px;
1020
1162
  color: var(--muted);
1021
- margin-top: 2px;
1022
1163
  white-space: nowrap;
1023
1164
  overflow: hidden;
1024
1165
  text-overflow: ellipsis;
1025
1166
  }
1026
1167
 
1168
+ /* Dans une liste, la pastille sert de repère, pas de portrait : elle est plus petite. */
1169
+ .thread-who .avatar--sm {
1170
+ width: 22px;
1171
+ height: 22px;
1172
+ font-size: 10px;
1173
+ }
1174
+
1175
+ /*
1176
+ Ici les pastilles ne se chevauchent pas. Le chevauchement du lecteur dit « ces gens vont
1177
+ ensemble » quand la place manque ; dans une liste qui se survole, il mange les initiales,
1178
+ et ce sont justement elles qui identifient la boîte. L'anneau qui détachait les pastilles
1179
+ superposées n'a alors plus rien à détacher.
1180
+ */
1181
+ .thread-who .avatar-stack {
1182
+ gap: 4px;
1183
+ }
1184
+
1185
+ .thread-who .avatar-stack .avatar + .avatar {
1186
+ margin-left: 0;
1187
+ }
1188
+
1189
+ .thread-who .avatar--stack {
1190
+ box-shadow: none;
1191
+ }
1192
+
1027
1193
  .thread-bottom {
1028
1194
  display: flex;
1029
1195
  align-items: center;
@@ -1 +1 @@
1
- export declare const APP_VERSION = "1.0.18";
1
+ export declare const APP_VERSION = "1.0.20";
@@ -1,2 +1,2 @@
1
1
  // Généré par scripts/generate-version.js — ne pas modifier à la main.
2
- export const APP_VERSION = "1.0.18";
2
+ export const APP_VERSION = "1.0.20";
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@imenam/mcp-messenger",
3
- "version": "1.0.18",
3
+ "version": "1.0.20",
4
4
  "main": "dist/src/index.js",
5
5
  "scripts": {
6
6
  "test": "npm run build && vitest run",