iron-cms 0.16.2 → 0.17.1

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.
@@ -27,9 +27,11 @@
27
27
  }
28
28
 
29
29
  @layer components {
30
- /* Editor container */
30
+ /* Editor container — must establish a positioning context so lexxy's
31
+ absolutely-positioned children (language picker, table tools, delete
32
+ buttons) anchor to the editor instead of leaking to the document. */
31
33
  lexxy-editor {
32
- @apply block w-full rounded-md;
34
+ @apply relative block w-full rounded-xl;
33
35
  @apply bg-white dark:bg-white/5;
34
36
  @apply border border-stone-950/10 dark:border-white/10;
35
37
  @apply focus-visible:outline-2 focus-visible:outline-sky-600 dark:focus-visible:outline-sky-500;
@@ -40,7 +42,7 @@
40
42
  @apply flex flex-wrap items-center gap-1 p-2;
41
43
  @apply border-b border-stone-950/10 dark:border-white/10;
42
44
  @apply bg-stone-50 dark:bg-white/5;
43
- @apply rounded-t-md;
45
+ @apply rounded-t-xl;
44
46
  }
45
47
 
46
48
  /* Toolbar button groups */
@@ -78,15 +80,15 @@
78
80
  fill: currentColor;
79
81
  }
80
82
 
81
- /* Editor content area */
82
- lexxy-editor [contenteditable] {
83
+ /* Editor content area — only the main editable surface, not decorator children */
84
+ lexxy-editor [contenteditable="true"] {
83
85
  @apply block w-full min-h-48 p-4;
84
86
  @apply text-base/6 text-stone-950 dark:text-white;
85
87
  @apply outline-none;
86
88
  @apply sm:text-sm/6;
87
89
  }
88
90
 
89
- lexxy-editor [contenteditable]:empty::before {
91
+ lexxy-editor [contenteditable="true"]:empty::before {
90
92
  content: attr(data-placeholder);
91
93
  @apply text-stone-400 dark:text-stone-500;
92
94
  @apply pointer-events-none;
@@ -126,12 +128,15 @@
126
128
  @apply rounded-ss-none;
127
129
  }
128
130
 
129
- .lexxy-editor__toolbar-dropdown:is([open]) .lexxy-editor__toolbar-button {
131
+ /* Active state for the dropdown's *trigger* (the <summary> itself, which carries
132
+ the toolbar-button class). Scope to direct summary so it doesn't bleed into
133
+ content buttons like highlight swatches that share the same class. */
134
+ .lexxy-editor__toolbar-dropdown:is([open]) > summary.lexxy-editor__toolbar-button {
130
135
  @apply bg-sky-100 dark:bg-sky-500/20;
131
136
  @apply rounded-ee-none rounded-es-none;
132
137
  }
133
138
 
134
- .lexxy-editor__toolbar-dropdown:is([open]) .lexxy-editor__toolbar-button:hover {
139
+ .lexxy-editor__toolbar-dropdown:is([open]) > summary.lexxy-editor__toolbar-button:hover {
135
140
  @apply bg-sky-100 dark:bg-sky-500/20;
136
141
  }
137
142
 
@@ -145,84 +150,138 @@
145
150
  @apply end-(--dropdown-padding) start-(--dropdown-padding);
146
151
  }
147
152
 
148
- /* Link dropdown */
153
+ /* Vertical dropdown menu (used by the text-formatting dropdown) — items show
154
+ an icon followed by a text label; needs to override toolbar's h-8 w-8 rule. */
155
+ .lexxy-editor__toolbar-dropdown-list {
156
+ @apply absolute z-10;
157
+ @apply flex flex-col p-1;
158
+ @apply bg-white dark:bg-stone-800;
159
+ @apply border-2 border-sky-200 dark:border-sky-500/30;
160
+ @apply rounded-md rounded-ss-none;
161
+ @apply text-stone-900 dark:text-white;
162
+ @apply top-8 start-0 min-w-[12rem];
163
+ }
164
+
165
+ .lexxy-editor__toolbar-dropdown-list button {
166
+ @apply w-auto h-auto justify-start;
167
+ @apply flex items-center gap-2 px-2 py-1.5 rounded;
168
+ @apply text-sm text-stone-700 dark:text-stone-200;
169
+ @apply text-start whitespace-nowrap;
170
+ @apply hover:bg-stone-100 dark:hover:bg-white/10;
171
+ }
172
+
173
+ .lexxy-editor__toolbar-dropdown-list button[aria-pressed="true"] {
174
+ @apply bg-sky-100 text-sky-900;
175
+ @apply dark:bg-sky-500/20 dark:text-sky-100;
176
+ }
177
+
178
+ .lexxy-editor__toolbar-dropdown-list button svg {
179
+ @apply size-4 flex-none;
180
+ fill: currentColor;
181
+ }
182
+
183
+ /* Lexxy emits explicit <div class="lexxy-editor__toolbar-separator"> elements
184
+ between groups inside the dropdown — relying on those means no extra
185
+ border-b for `group-end` (which would double up the divider). */
186
+ .lexxy-editor__toolbar-dropdown-list .lexxy-editor__toolbar-separator {
187
+ @apply my-1 h-px w-full;
188
+ @apply bg-stone-200 dark:bg-white/10;
189
+ }
190
+
191
+ /* Link dropdown — URL input with Link / Unlink action buttons */
149
192
  lexxy-link-dropdown {
150
- @apply flex-1;
193
+ @apply gap-2 min-w-[22rem];
151
194
  }
152
195
 
153
- lexxy-link-dropdown > * {
154
- @apply flex-1;
196
+ [overflowing] lexxy-link-dropdown {
197
+ @apply min-w-0 flex-col;
155
198
  }
156
199
 
157
- lexxy-link-dropdown .lexxy-editor__toolbar-dropdown-actions {
158
- @apply flex flex-1 gap-2 mt-2;
159
- @apply text-sm;
200
+ [overflowing] lexxy-link-dropdown .lexxy-editor__toolbar-dropdown-actions {
201
+ @apply mt-2;
160
202
  }
161
203
 
162
204
  lexxy-link-dropdown input[type="url"] {
163
- @apply w-full rounded-md px-2;
205
+ @apply flex-1 min-w-0;
206
+ @apply h-8 px-2 rounded-md;
164
207
  @apply border border-stone-300 dark:border-white/10;
165
208
  @apply bg-white dark:bg-stone-900;
166
- @apply text-stone-900 dark:text-white;
209
+ @apply text-sm leading-none text-stone-900 dark:text-white;
167
210
  @apply placeholder:text-stone-400 dark:placeholder:text-stone-500;
168
- @apply focus-visible:outline-2 focus-visible:outline-sky-600 dark:focus-visible:outline-sky-500;
169
- @apply leading-6 min-w-[40ch] box-border;
211
+ @apply outline-none;
212
+ @apply focus-visible:outline-2 focus-visible:outline-offset-1 focus-visible:outline-sky-600 focus-visible:border-transparent dark:focus-visible:outline-sky-500;
170
213
  }
171
214
 
172
- [overflowing] lexxy-link-dropdown input[type="url"] {
173
- @apply min-w-0;
215
+ lexxy-link-dropdown .lexxy-editor__toolbar-dropdown-actions {
216
+ @apply flex flex-none items-center gap-2;
174
217
  }
175
218
 
219
+ /* Override toolbar's h-8 w-8 — these buttons need to fit their text label */
176
220
  lexxy-link-dropdown .lexxy-editor__toolbar-dropdown-actions button {
177
- @apply w-full justify-center;
178
- @apply button-secondary button-sm;
221
+ @apply w-auto h-8 px-3;
222
+ @apply text-sm font-medium leading-none;
223
+ @apply rounded-md;
179
224
  }
180
225
 
181
- /* Highlight/Color dropdown */
182
- lexxy-highlight-dropdown {
183
- @apply flex flex-col;
226
+ lexxy-link-dropdown .lexxy-editor__toolbar-dropdown-actions button[value="link"] {
227
+ @apply bg-sky-600 text-white;
228
+ @apply hover:bg-sky-700;
184
229
  }
185
230
 
186
- lexxy-highlight-dropdown [data-button-group] {
187
- @apply flex flex-row gap-(--dropdown-gap);
188
- @apply justify-start;
231
+ lexxy-link-dropdown .lexxy-editor__toolbar-dropdown-actions button[value="unlink"] {
232
+ @apply bg-white dark:bg-white/10;
233
+ @apply text-stone-700 dark:text-stone-200;
234
+ @apply ring-1 ring-inset ring-stone-300 dark:ring-white/15;
235
+ @apply hover:bg-stone-50 dark:hover:bg-white/15;
189
236
  }
190
237
 
191
- lexxy-highlight-dropdown [data-button-group] button {
238
+ /* Highlight/Color dropdown
239
+ Lexxy 0.9.9 emits 9 text-color buttons followed by 9 bg-color buttons.
240
+ With `grid-auto-flow: column` and 2 rows, source order fills col-by-col so
241
+ each column shows a matching color/bg pair (row 1 = color, row 2 = bg). */
242
+ lexxy-highlight-dropdown {
192
243
  --button-size: --spacing(8);
193
- @apply aspect-square;
194
- @apply w-(--button-size) min-w-(--button-size) max-w-(--button-size);
244
+ @apply flex flex-col gap-2;
195
245
  }
196
246
 
197
- lexxy-highlight-dropdown [data-button-group] button::after {
198
- content: "Aa";
199
- @apply absolute inset-0;
200
- @apply self-center;
201
- @apply inline-block;
247
+ lexxy-highlight-dropdown .lexxy-highlight-colors {
248
+ display: grid;
249
+ grid-template-columns: repeat(var(--max-colors, 9), var(--button-size));
250
+ grid-template-rows: repeat(2, var(--button-size));
251
+ grid-auto-flow: column;
252
+ @apply gap-1;
253
+ }
254
+
255
+ lexxy-highlight-dropdown .lexxy-highlight-button {
256
+ @apply relative aspect-square size-8 rounded-md p-0;
257
+ @apply ring-1 ring-inset ring-stone-300 dark:ring-white/15;
258
+ @apply hover:opacity-80;
202
259
  font-family: system-ui, -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif;
203
260
  }
204
261
 
205
- lexxy-highlight-dropdown button {
206
- --button-size: --spacing(8);
207
- @apply flex-1 relative;
208
- @apply text-stone-900 dark:text-white;
209
- @apply min-h-(--button-size);
262
+ lexxy-highlight-dropdown .lexxy-highlight-button::after {
263
+ content: "Aa";
264
+ @apply absolute inset-0 flex items-center justify-center;
265
+ @apply font-semibold text-sm leading-none;
210
266
  }
211
267
 
212
- lexxy-highlight-dropdown button:hover {
213
- @apply opacity-80;
268
+ /* Background-color button: letter in default ink color over the swatch */
269
+ lexxy-highlight-dropdown .lexxy-highlight-button[data-style="background-color"]::after {
270
+ @apply text-stone-900 dark:text-white;
214
271
  }
215
272
 
216
- lexxy-highlight-dropdown button[aria-pressed="true"] {
217
- @apply ring-2 ring-inset ring-current;
273
+ /* Selected state — transparent bg with a thick inset ring in the swatch's color */
274
+ lexxy-highlight-dropdown .lexxy-highlight-button[aria-pressed="true"] {
275
+ background-color: transparent;
276
+ box-shadow: inset 0 0 0 2px currentColor;
218
277
  }
219
278
 
220
- lexxy-highlight-dropdown button[aria-pressed="true"]::after {
279
+ lexxy-highlight-dropdown .lexxy-highlight-button[aria-pressed="true"]::after {
221
280
  content: "✓";
222
281
  }
223
282
 
224
283
  lexxy-highlight-dropdown .lexxy-editor__toolbar-dropdown-reset {
225
- @apply mt-2 w-full;
284
+ @apply mt-2 w-full whitespace-nowrap;
226
285
  @apply button-secondary button-sm;
227
286
  }
228
287
 
@@ -230,23 +289,11 @@
230
289
  @apply hidden;
231
290
  }
232
291
 
233
- /* Responsive highlight dropdown */
292
+ /* Responsive highlight dropdown — overflow menu is narrower */
234
293
  [overflowing] lexxy-highlight-dropdown {
235
294
  @apply w-fit;
236
295
  }
237
296
 
238
- [overflowing] lexxy-highlight-dropdown [data-button-group] {
239
- @apply flex-wrap;
240
- }
241
-
242
- [overflowing] lexxy-highlight-dropdown [data-button-group] button {
243
- --button-size: --spacing(6);
244
- }
245
-
246
- [overflowing] lexxy-highlight-dropdown [data-button-group] button::after {
247
- @apply text-sm;
248
- }
249
-
250
297
  /* Attachment upload progress */
251
298
  lexxy-editor .attachment__progress {
252
299
  @apply absolute z-10;
@@ -317,6 +364,265 @@
317
364
  lexxy-editor .attachment.selected img {
318
365
  @apply ring-2 ring-sky-500;
319
366
  }
367
+
368
+ /* Block-level node selection (hr, attachments, tables, galleries) */
369
+ lexxy-editor .node--selected {
370
+ @apply outline-2 outline-offset-2 outline-sky-500;
371
+ @apply rounded;
372
+ }
373
+
374
+ /* Floating controls (delete button, table tools, etc.) */
375
+ .lexxy-floating-controls {
376
+ @apply absolute z-10;
377
+ @apply text-white text-sm leading-none;
378
+ }
379
+
380
+ .lexxy-floating-controls .lexxy-floating-controls__group {
381
+ @apply flex items-center gap-0.5 p-0.5 rounded-md;
382
+ @apply bg-stone-900/90 dark:bg-stone-700;
383
+ @apply shadow-md;
384
+ }
385
+
386
+ .lexxy-floating-controls button,
387
+ .lexxy-floating-controls summary {
388
+ @apply inline-flex items-center justify-center;
389
+ @apply h-7 min-w-7 px-1 rounded;
390
+ @apply text-white hover:bg-white/15;
391
+ @apply focus-visible:outline-2 focus-visible:outline-sky-400;
392
+ @apply select-none cursor-pointer;
393
+ }
394
+
395
+ .lexxy-floating-controls svg {
396
+ @apply size-4;
397
+ fill: currentColor;
398
+ }
399
+
400
+ lexxy-node-delete-button .lexxy-node-delete:hover {
401
+ @apply bg-red-600;
402
+ }
403
+
404
+ /* Tables in the editor */
405
+ lexxy-editor table {
406
+ @apply w-full !my-0 border-collapse text-sm;
407
+ }
408
+
409
+ lexxy-editor th,
410
+ lexxy-editor td {
411
+ @apply relative border border-stone-300 dark:border-stone-600;
412
+ @apply px-3 py-2 text-start align-top;
413
+ @apply min-w-[5ch];
414
+ transition: all 0.1s ease-in-out;
415
+ }
416
+
417
+ /* Each cell carries a positioned ::after used as an overlay for focus, row /
418
+ column insertion lines, and other transient visualizations. Inset by -1px
419
+ so the box-shadow can paint across the cell border. */
420
+ lexxy-editor th::after,
421
+ lexxy-editor td::after {
422
+ content: "";
423
+ @apply absolute pointer-events-none block;
424
+ inset: -1px;
425
+ z-index: 2;
426
+ box-shadow: 0 0 0 0 transparent, 0 0 0 0 transparent inset;
427
+ transition: box-shadow 0.1s ease-in-out;
428
+ }
429
+
430
+ lexxy-editor th,
431
+ lexxy-editor .lexxy-content__table-cell--header {
432
+ @apply bg-stone-100 dark:bg-white/10 font-semibold;
433
+ @apply text-stone-950 dark:text-white;
434
+ }
435
+
436
+ lexxy-editor td.lexxy-content__table-cell--selected,
437
+ lexxy-editor th.lexxy-content__table-cell--selected {
438
+ @apply bg-sky-100/60 dark:bg-sky-500/15;
439
+ }
440
+
441
+ /* Focused cell — 2px inset blue border via the shared ::after */
442
+ lexxy-editor td.lexxy-content__table-cell--focus::after,
443
+ lexxy-editor th.lexxy-content__table-cell--focus::after {
444
+ box-shadow: 0 0 0 0 transparent, 0 0 0 2px var(--color-sky-500) inset;
445
+ }
446
+
447
+ /* Variables for the row/column insertion indicator */
448
+ lexxy-editor table {
449
+ --lexxy-cell-add-size: 2px;
450
+ --lexxy-cell-add-color: var(--color-sky-500);
451
+ }
452
+
453
+ /* Insertion indicator — a thick line straddling the cell edge where the new
454
+ row or column will appear. Built from two stacked box-shadows: one outside
455
+ the cell and one inset, so the line spans the 1px border. */
456
+ lexxy-editor td.lexxy-content__table-cell--highlight[data-action="insert"][data-child-type="row"][data-direction="after"]::after,
457
+ lexxy-editor th.lexxy-content__table-cell--highlight[data-action="insert"][data-child-type="row"][data-direction="after"]::after {
458
+ box-shadow:
459
+ 0 var(--lexxy-cell-add-size) 0 0 var(--lexxy-cell-add-color),
460
+ 0 calc(-1 * var(--lexxy-cell-add-size) - 1px) 0 0 var(--lexxy-cell-add-color) inset;
461
+ }
462
+
463
+ lexxy-editor td.lexxy-content__table-cell--highlight[data-action="insert"][data-child-type="row"][data-direction="before"]::after,
464
+ lexxy-editor th.lexxy-content__table-cell--highlight[data-action="insert"][data-child-type="row"][data-direction="before"]::after {
465
+ box-shadow:
466
+ 0 calc(-1 * var(--lexxy-cell-add-size) - 1px) 0 0 var(--lexxy-cell-add-color),
467
+ 0 var(--lexxy-cell-add-size) 0 0 var(--lexxy-cell-add-color) inset;
468
+ }
469
+
470
+ lexxy-editor td.lexxy-content__table-cell--highlight[data-action="insert"][data-child-type="column"][data-direction="after"]::after,
471
+ lexxy-editor th.lexxy-content__table-cell--highlight[data-action="insert"][data-child-type="column"][data-direction="after"]::after {
472
+ box-shadow:
473
+ var(--lexxy-cell-add-size) 0 0 0 var(--lexxy-cell-add-color),
474
+ calc(-1 * var(--lexxy-cell-add-size) - 1px) 0 0 0 var(--lexxy-cell-add-color) inset;
475
+ }
476
+
477
+ lexxy-editor td.lexxy-content__table-cell--highlight[data-action="insert"][data-child-type="column"][data-direction="before"]::after,
478
+ lexxy-editor th.lexxy-content__table-cell--highlight[data-action="insert"][data-child-type="column"][data-direction="before"]::after {
479
+ box-shadow:
480
+ calc(-1 * var(--lexxy-cell-add-size) - 1px) 0 0 0 var(--lexxy-cell-add-color),
481
+ var(--lexxy-cell-add-size) 0 0 0 var(--lexxy-cell-add-color) inset;
482
+ }
483
+
484
+ /* Toggle (style change) — subtle blue tint on the affected row/column */
485
+ lexxy-editor td.lexxy-content__table-cell--highlight[data-action="toggle"],
486
+ lexxy-editor th.lexxy-content__table-cell--highlight[data-action="toggle"],
487
+ lexxy-editor tr.lexxy-content__table-cell--highlight[data-action="toggle"] th,
488
+ lexxy-editor tr.lexxy-content__table-cell--highlight[data-action="toggle"] td {
489
+ @apply bg-sky-500/10;
490
+ }
491
+
492
+ /* Delete — red tint on the row/column/table about to be removed */
493
+ lexxy-editor td.lexxy-content__table-cell--highlight[data-action="delete"],
494
+ lexxy-editor th.lexxy-content__table-cell--highlight[data-action="delete"],
495
+ lexxy-editor tr.lexxy-content__table-cell--highlight[data-action="delete"] th,
496
+ lexxy-editor tr.lexxy-content__table-cell--highlight[data-action="delete"] td {
497
+ @apply bg-red-500/10 text-red-600 dark:text-red-400;
498
+ }
499
+
500
+ .lexxy-content__table-wrapper {
501
+ @apply overflow-x-auto my-4;
502
+ }
503
+
504
+ /* Floating table tools — three chip-style groups (row, column, delete) laid
505
+ out horizontally. Group chrome (background, rounding, shadow) comes from
506
+ the shared .lexxy-floating-controls__group rule above. Lexxy positions
507
+ the element with `left` at the table's horizontal midpoint and `top` at
508
+ the table's top edge; translate it back by half its width and above its
509
+ own height so it sits centered just above the table instead of overlaying
510
+ the first row. */
511
+ lexxy-table-tools {
512
+ @apply absolute z-10 flex flex-row items-start gap-1;
513
+ @apply text-white text-sm leading-none;
514
+ @apply -translate-x-1/2 -translate-y-[calc(100%+4px)];
515
+ }
516
+
517
+ /* Icon-only buttons are square; summary stays auto-width so its count text
518
+ ("3 rows") can render inline. Apply only to direct children of the row /
519
+ column / delete groups so menu items inside the dropdown can grow. */
520
+ lexxy-table-tools .lexxy-table-control > .lexxy-table-control__button {
521
+ @apply w-7 font-bold;
522
+ }
523
+
524
+ /* Hide redundant text labels — aria-label keeps the buttons accessible. */
525
+ lexxy-table-tools .lexxy-table-control__button > span {
526
+ @apply hidden;
527
+ }
528
+
529
+ /* Summary holds the visible row/column count; suppress the default marker */
530
+ lexxy-table-tools summary {
531
+ list-style: none;
532
+ @apply font-normal whitespace-nowrap cursor-pointer;
533
+ }
534
+
535
+ lexxy-table-tools summary::-webkit-details-marker {
536
+ display: none;
537
+ }
538
+
539
+ lexxy-table-tools summary::marker {
540
+ content: "";
541
+ }
542
+
543
+ /* More-menu dropdown anchors directly under its summary */
544
+ lexxy-table-tools .lexxy-table-control__more-menu {
545
+ @apply relative;
546
+ }
547
+
548
+ lexxy-table-tools .lexxy-table-control__more-menu-details {
549
+ @apply absolute z-10 top-full start-1/2 mt-1 -translate-x-1/2 min-w-max;
550
+ @apply flex flex-col items-stretch gap-0.5 p-1 rounded-md;
551
+ @apply bg-stone-900 dark:bg-stone-700 shadow-md;
552
+ }
553
+
554
+ /* Inside the dropdown, buttons are full-width menu rows with icon + label */
555
+ lexxy-table-tools .lexxy-table-control__more-menu-details .lexxy-table-control__button {
556
+ @apply w-full h-auto justify-start gap-2 px-2 py-1.5;
557
+ @apply font-normal whitespace-nowrap;
558
+ }
559
+
560
+ lexxy-table-tools .lexxy-table-control__more-menu-details .lexxy-table-control__button > span {
561
+ @apply inline-block;
562
+ }
563
+
564
+ /* Delete-table — destructive hover state, with a confirmation tooltip
565
+ floating above the icon. */
566
+ lexxy-table-tools .lexxy-table-control__button--delete-table {
567
+ @apply relative;
568
+ }
569
+
570
+ lexxy-table-tools .lexxy-table-control__button--delete-table:hover {
571
+ @apply bg-red-600;
572
+ }
573
+
574
+ lexxy-table-tools .lexxy-table-control__button--delete-table > span {
575
+ @apply absolute z-20 bottom-full left-1/2 mb-1 -translate-x-1/2;
576
+ @apply inline-flex items-center h-7 px-2 rounded-md;
577
+ @apply bg-stone-900 dark:bg-stone-700 whitespace-nowrap;
578
+ @apply opacity-0 pointer-events-none transition-opacity;
579
+ }
580
+
581
+ lexxy-table-tools .lexxy-table-control__button--delete-table:hover > span {
582
+ @apply opacity-100;
583
+ }
584
+
585
+ /* Drag/drop indicators — vertical line between gallery attachments,
586
+ horizontal line above/below blocks and list items. */
587
+ [class*="lexxy-drop-target--"] {
588
+ @apply relative;
589
+ }
590
+
591
+ .lexxy-drop-target--gallery-before::before,
592
+ .lexxy-drop-target--gallery-after::after {
593
+ content: "";
594
+ @apply absolute inset-y-0 w-[3px] rounded-sm;
595
+ @apply bg-sky-600 dark:bg-sky-500;
596
+ @apply pointer-events-none;
597
+ }
598
+
599
+ .lexxy-drop-target--gallery-before::before {
600
+ inset-inline-start: -4px;
601
+ }
602
+
603
+ .lexxy-drop-target--gallery-after::after {
604
+ inset-inline-end: -4px;
605
+ }
606
+
607
+ .lexxy-drop-target--block-before::before,
608
+ .lexxy-drop-target--block-after::after,
609
+ .lexxy-drop-target--list-before::before,
610
+ .lexxy-drop-target--list-after::after {
611
+ content: "";
612
+ @apply absolute inset-x-0 h-[3px] rounded-sm;
613
+ @apply bg-sky-600 dark:bg-sky-500;
614
+ @apply pointer-events-none;
615
+ }
616
+
617
+ .lexxy-drop-target--block-before::before,
618
+ .lexxy-drop-target--list-before::before {
619
+ inset-block-start: -2px;
620
+ }
621
+
622
+ .lexxy-drop-target--block-after::after,
623
+ .lexxy-drop-target--list-after::after {
624
+ inset-block-end: -2px;
625
+ }
320
626
  }
321
627
 
322
628
  /* Rendered content styles */
@@ -419,6 +725,33 @@
419
725
  @apply my-4;
420
726
  }
421
727
 
728
+ /* Tables */
729
+ .lexxy-content .lexxy-content__table-wrapper {
730
+ @apply my-4 overflow-x-auto;
731
+ }
732
+
733
+ .lexxy-content table {
734
+ @apply w-full border-collapse text-sm;
735
+ @apply my-4;
736
+ }
737
+
738
+ .lexxy-content th,
739
+ .lexxy-content td {
740
+ @apply border border-stone-300 dark:border-stone-600;
741
+ @apply px-3 py-2 text-start align-top;
742
+ }
743
+
744
+ .lexxy-content th,
745
+ .lexxy-content .lexxy-content__table-cell--header {
746
+ @apply bg-stone-100 dark:bg-white/10 font-semibold;
747
+ @apply text-stone-950 dark:text-white;
748
+ }
749
+
750
+ .lexxy-content th *:last-child,
751
+ .lexxy-content td *:last-child {
752
+ @apply mb-0;
753
+ }
754
+
422
755
  /* Attachment rendering in content */
423
756
  .lexxy-content .attachment {
424
757
  @apply inline-block max-w-full my-4;
@@ -478,3 +811,85 @@
478
811
  @apply p-0 max-w-full my-0;
479
812
  }
480
813
  }
814
+
815
+ /*
816
+ * Editor overrides that must beat Tailwind Typography (prose) rules.
817
+ * The prose plugin emits its `figure`, `hr`, `table`, `code`, etc. selectors
818
+ * in the utilities layer with `:where()` (zero specificity), so layer-order
819
+ * is what matters: keep these in @layer utilities so they win.
820
+ */
821
+ @layer utilities {
822
+ /* Horizontal divider — lexxy wraps the <hr> in <figure class="horizontal-divider"> */
823
+ lexxy-editor figure.horizontal-divider {
824
+ @apply relative m-0 px-0 py-3 text-center;
825
+ }
826
+
827
+ lexxy-editor figure.horizontal-divider hr {
828
+ @apply inline-block h-px w-1/5 m-0 p-0 border-0;
829
+ @apply bg-stone-300 dark:bg-stone-600;
830
+ }
831
+
832
+ /* Per-node delete button (appears on hover or selection) */
833
+ lexxy-node-delete-button {
834
+ @apply absolute z-10 opacity-0 pointer-events-none transition-opacity;
835
+ inset-block-start: 0.25rem;
836
+ inset-inline-end: 0.25rem;
837
+ inset-inline-start: auto;
838
+ }
839
+
840
+ lexxy-editor figure:hover > lexxy-node-delete-button,
841
+ lexxy-editor .attachment:hover > lexxy-node-delete-button,
842
+ lexxy-editor .node--selected > lexxy-node-delete-button,
843
+ lexxy-editor .node--selected lexxy-node-delete-button {
844
+ @apply opacity-100 pointer-events-auto;
845
+ }
846
+
847
+ /* Tailwind Typography wraps inline <code> with backtick pseudo-elements; suppress them */
848
+ lexxy-editor.prose code::before,
849
+ lexxy-editor.prose code::after,
850
+ .lexxy-content code::before,
851
+ .lexxy-content code::after {
852
+ content: none;
853
+ }
854
+
855
+ /* Inline code in the editor */
856
+ lexxy-editor code:not([data-language]) {
857
+ @apply px-1.5 py-0.5 rounded;
858
+ @apply bg-stone-100 dark:bg-white/10;
859
+ @apply text-sm font-mono;
860
+ @apply text-pink-600 dark:text-pink-400;
861
+ }
862
+
863
+ /* Code blocks (lexxy renders them as <code data-language="..."> with display:inline by default;
864
+ we promote to a block container so the language picker has somewhere to anchor.
865
+ Extra top padding leaves room for the picker chip in the top-right corner. */
866
+ lexxy-editor code[data-language] {
867
+ @apply relative block my-4 px-4 pb-4 pt-10 rounded-lg overflow-x-auto;
868
+ @apply bg-stone-100 dark:bg-stone-900;
869
+ @apply text-sm font-mono leading-relaxed;
870
+ @apply text-stone-900 dark:text-stone-100;
871
+ @apply whitespace-pre;
872
+ }
873
+
874
+ /* Language picker — replace the native <select> with a styled chip in the
875
+ code block's corner. Lexxy's JS sets inline top/right to anchor it to the
876
+ active code block; we add margins so it sits slightly inset from the edge. */
877
+ lexxy-code-language-picker select {
878
+ @apply appearance-none cursor-pointer;
879
+ @apply bg-white dark:bg-stone-800;
880
+ @apply border border-stone-300 dark:border-white/15;
881
+ @apply rounded-md;
882
+ @apply text-stone-700 dark:text-stone-200;
883
+ @apply text-xs font-medium leading-none;
884
+ @apply pl-2 pr-6 py-1;
885
+ @apply mt-2 mr-2;
886
+ background-image: url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='currentColor' stroke-width='2.5' stroke-linecap='round' stroke-linejoin='round'><polyline points='6 9 12 15 18 9'/></svg>");
887
+ background-repeat: no-repeat;
888
+ background-position: right 0.5rem center;
889
+ background-size: 0.7rem;
890
+ }
891
+
892
+ lexxy-code-language-picker select:focus-visible {
893
+ @apply outline-2 outline-sky-600 dark:outline-sky-500;
894
+ }
895
+ }
@@ -31,7 +31,7 @@ module Iron
31
31
 
32
32
  path = File.join(dir, entry.name.sub("files/", ""))
33
33
  FileUtils.mkdir_p(File.dirname(path))
34
- entry.extract(path)
34
+ File.binwrite(path, entry.get_input_stream.read)
35
35
  end
36
36
  dir
37
37
  end
data/lib/iron/version.rb CHANGED
@@ -1,3 +1,3 @@
1
1
  module Iron
2
- VERSION = "0.16.2"
2
+ VERSION = "0.17.1"
3
3
  end