@miliastry/quasar 1.0.4 → 1.0.6

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.
@@ -249,8 +249,8 @@
249
249
  * del autor ([boxw=Title:#hex]) si lo hay; si no, el hairline del tema. */
250
250
  .bbcode-preview-lyne details.boxw,
251
251
  .bbcode-preview.theme-lyne details.boxw {
252
- background: rgba(11, 16, 36, 0.5) !important;
253
- border: 1px solid var(--box-accent, var(--card-accent, var(--glass-accent, var(--color-hairline, rgba(255, 255, 255, 0.12))))) !important;
252
+ background: var(--box-bg, rgba(11, 16, 36, 0.5)) !important;
253
+ border: 1px solid var(--box-border, var(--box-accent, var(--card-accent, var(--glass-accent, var(--color-hairline, rgba(255, 255, 255, 0.12)))))) !important;
254
254
  border-radius: 0 !important;
255
255
  clip-path: polygon(8px 0, 100% 0, 100% calc(100% - 8px), calc(100% - 8px) 100%, 0 100%, 0 8px) !important;
256
256
  padding: 0 !important;
@@ -331,8 +331,8 @@
331
331
  width: 7px !important;
332
332
  height: 7px !important;
333
333
  flex: 0 0 7px !important;
334
- border-right: 1.5px solid currentColor !important;
335
- border-bottom: 1.5px solid currentColor !important;
334
+ border-right: 1px solid currentColor !important;
335
+ border-bottom: 1px solid currentColor !important;
336
336
  transform: rotate(-45deg) !important;
337
337
  transition: transform 0.15s ease !important;
338
338
  }
@@ -360,7 +360,7 @@
360
360
 
361
361
  .bbcode-preview-lyne details.boxw[open] > summary,
362
362
  .bbcode-preview.theme-lyne details.boxw[open] > summary {
363
- border-bottom: 1px solid var(--box-accent, var(--card-accent, var(--glass-accent, var(--color-hairline, rgba(255, 255, 255, 0.12))))) !important;
363
+ border-bottom: 1px solid var(--box-border, var(--box-accent, var(--card-accent, var(--glass-accent, var(--color-hairline, rgba(255, 255, 255, 0.12)))))) !important;
364
364
  }
365
365
 
366
366
  .bbcode-preview-lyne details[open] > summary::before,
@@ -370,7 +370,8 @@
370
370
 
371
371
  .bbcode-preview-lyne details > summary:hover,
372
372
  .bbcode-preview.theme-lyne details > summary:hover {
373
- color: var(--color-accent-bright, #68FFF8) !important;
373
+ color: var(--box-accent, var(--card-accent, var(--glass-accent, var(--color-accent-bright, #68FFF8)))) !important;
374
+ filter: brightness(1.25) !important;
374
375
  }
375
376
 
376
377
  /* ─── Lists & Markers ───────────────────────────────────────────────────── */
@@ -469,6 +470,7 @@
469
470
  .bb-table {
470
471
  width: 100% !important;
471
472
  min-width: 380px !important;
473
+ table-layout: fixed !important;
472
474
  border-collapse: separate !important;
473
475
  border-spacing: 0 !important;
474
476
  margin: 0 !important;
@@ -518,6 +520,64 @@
518
520
  line-height: 1.3 !important;
519
521
  text-transform: uppercase !important;
520
522
  padding: 8px 10px !important;
523
+ text-align: left !important;
524
+ }
525
+
526
+ .bb-table .bb-th.bb-th-full {
527
+ width: 100% !important;
528
+ }
529
+
530
+ /* Table header alignments */
531
+ .bb-table .bb-th.bb-th-left,
532
+ .bb-table .bb-th:has(.bb-left),
533
+ .bb-table .bb-th:has([style*="text-align:left"]),
534
+ .bb-table .bb-th:has([style*="text-align: left"]),
535
+ .bb-left .bb-table .bb-th {
536
+ text-align: left !important;
537
+ }
538
+
539
+ .bb-table .bb-th.bb-th-left .bb-table-badge,
540
+ .bb-table .bb-th:has(.bb-left) .bb-table-badge,
541
+ .bb-table .bb-th:has([style*="text-align:left"]) .bb-table-badge,
542
+ .bb-table .bb-th:has([style*="text-align: left"]) .bb-table-badge,
543
+ .bb-left .bb-table .bb-th .bb-table-badge {
544
+ margin-right: auto !important;
545
+ margin-left: 0 !important;
546
+ }
547
+
548
+ .bb-table .bb-th.bb-th-centered,
549
+ .bb-table .bb-th.bb-th-center,
550
+ .bb-table .bb-th:has(.bb-centre),
551
+ .bb-table .bb-th:has([style*="text-align:center"]),
552
+ .bb-table .bb-th:has([style*="text-align: center"]),
553
+ .bb-centre .bb-table .bb-th {
554
+ text-align: center !important;
555
+ }
556
+
557
+ .bb-table .bb-th.bb-th-centered .bb-table-badge,
558
+ .bb-table .bb-th.bb-th-center .bb-table-badge,
559
+ .bb-table .bb-th:has(.bb-centre) .bb-table-badge,
560
+ .bb-table .bb-th:has([style*="text-align:center"]) .bb-table-badge,
561
+ .bb-table .bb-th:has([style*="text-align: center"]) .bb-table-badge,
562
+ .bb-centre .bb-table .bb-th .bb-table-badge {
563
+ margin: 0 auto !important;
564
+ }
565
+
566
+ .bb-table .bb-th.bb-th-right,
567
+ .bb-table .bb-th:has(.bb-right),
568
+ .bb-table .bb-th:has([style*="text-align:right"]),
569
+ .bb-table .bb-th:has([style*="text-align: right"]),
570
+ .bb-right .bb-table .bb-th {
571
+ text-align: right !important;
572
+ }
573
+
574
+ .bb-table .bb-th.bb-th-right .bb-table-badge,
575
+ .bb-table .bb-th:has(.bb-right) .bb-table-badge,
576
+ .bb-table .bb-th:has([style*="text-align:right"]) .bb-table-badge,
577
+ .bb-table .bb-th:has([style*="text-align: right"]) .bb-table-badge,
578
+ .bb-right .bb-table .bb-th .bb-table-badge {
579
+ margin-left: auto !important;
580
+ margin-right: 0 !important;
521
581
  }
522
582
 
523
583
  .bb-table-badge {
@@ -610,7 +670,7 @@
610
670
  border: 0 !important;
611
671
  height: 1px !important;
612
672
  background: linear-gradient(90deg, transparent, var(--color-accent, #2EE6E2), transparent) !important;
613
- margin: 0 !important;
673
+ margin: 12px 0 !important;
614
674
  text-align: center !important;
615
675
  color: var(--color-accent, #2EE6E2) !important;
616
676
  font-family: var(--font-numeric, monospace) !important;
@@ -733,7 +793,7 @@
733
793
  .bb-neon-box {
734
794
  padding: 16px !important;
735
795
  margin: 0 !important;
736
- border: 2px solid var(--neon-color, var(--color-accent, #2EE6E2)) !important;
796
+ border: 1px solid var(--neon-color, var(--color-accent, #2EE6E2)) !important;
737
797
  background: color-mix(in srgb, var(--neon-color, var(--color-accent, #2EE6E2)) 4%, rgba(7, 10, 23, 0.55)) !important;
738
798
  border-radius: 0 !important;
739
799
  box-shadow: none !important;
@@ -758,20 +818,26 @@
758
818
  align-items: center !important;
759
819
  }
760
820
 
761
- /* Circle: replica el .bbCircle original de Lyne (Main Bridge/line/web/
762
- * components/bbcode.module.css). aspect-ratio:1 + centrado convierten el div
763
- * en un círculo real con el contenido al centro; fondo y borde lo pintan como
764
- * badge. clip-path:none evita que herede los cortes de esquina de los paneles. */
821
+ /* Square: cuadradito badge con las muescas angulares características de Lyne.
822
+ * aspect-ratio: 1/1, centrado, borde hairline y corte angular de esquina. */
823
+ .bb-square,
765
824
  .bb-circle {
766
825
  display: inline-flex !important;
767
826
  align-items: center !important;
768
827
  justify-content: center !important;
769
- aspect-ratio: 1 !important;
770
- border-radius: 50% !important;
828
+ aspect-ratio: 1 / 1 !important;
829
+ min-width: 1.85em !important;
830
+ min-height: 1.85em !important;
831
+ padding: 0.2em 0.35em !important;
832
+ box-sizing: border-box !important;
833
+ border-radius: 0 !important;
771
834
  overflow: hidden !important;
772
- background: rgb(11 16 36 / 0.5) !important;
773
- border: 1px solid var(--color-hairline, rgba(255, 255, 255, 0.12)) !important;
774
- clip-path: none !important;
835
+ background: var(--square-bg, rgb(11 16 36 / 0.5)) !important;
836
+ border: 1px solid var(--square-border, var(--square-accent, var(--color-hairline, rgba(255, 255, 255, 0.12)))) !important;
837
+ clip-path: polygon(4px 0, 100% 0, 100% calc(100% - 4px), calc(100% - 4px) 100%, 0 100%, 0 4px) !important;
838
+ text-align: center !important;
839
+ line-height: 1 !important;
840
+ vertical-align: middle !important;
775
841
  }
776
842
 
777
843
  /* Stack: replica el .bbStack original de Lyne (columna flex con gap).
package/dist/index.d.mts CHANGED
@@ -2458,6 +2458,8 @@ declare class HTMLRenderer extends Visitor<string> {
2458
2458
  private static readonly CSS_FONT_RE;
2459
2459
  /** Characters `escapeHtml` has to rewrite. Non-global on purpose: `test` must not carry `lastIndex`. */
2460
2460
  private static readonly HTML_ESCAPE_RE;
2461
+ private static readonly BARE_HEX_RE;
2462
+ private static readonly NAMED_COLORS;
2461
2463
  private sanitizeColor;
2462
2464
  private sanitizeFontSize;
2463
2465
  private sanitizeFontFamily;
@@ -2487,6 +2489,7 @@ declare class HTMLRenderer extends Visitor<string> {
2487
2489
  private hexToRgba;
2488
2490
  private renderNotice;
2489
2491
  private renderTables;
2492
+ private getTableContext;
2490
2493
  private renderGallery;
2491
2494
  private renderColumns;
2492
2495
  private renderSeparator;
package/dist/index.d.ts CHANGED
@@ -2458,6 +2458,8 @@ declare class HTMLRenderer extends Visitor<string> {
2458
2458
  private static readonly CSS_FONT_RE;
2459
2459
  /** Characters `escapeHtml` has to rewrite. Non-global on purpose: `test` must not carry `lastIndex`. */
2460
2460
  private static readonly HTML_ESCAPE_RE;
2461
+ private static readonly BARE_HEX_RE;
2462
+ private static readonly NAMED_COLORS;
2461
2463
  private sanitizeColor;
2462
2464
  private sanitizeFontSize;
2463
2465
  private sanitizeFontFamily;
@@ -2487,6 +2489,7 @@ declare class HTMLRenderer extends Visitor<string> {
2487
2489
  private hexToRgba;
2488
2490
  private renderNotice;
2489
2491
  private renderTables;
2492
+ private getTableContext;
2490
2493
  private renderGallery;
2491
2494
  private renderColumns;
2492
2495
  private renderSeparator;
package/dist/index.js CHANGED
@@ -1548,6 +1548,7 @@ var LYNE_LEGACY_ALIASES = {
1548
1548
  "flex": "container",
1549
1549
  "grid": "container",
1550
1550
  "middle": "container",
1551
+ "square": "container",
1551
1552
  "circle": "container",
1552
1553
  "card": "container",
1553
1554
  "glass": "container",
@@ -1711,6 +1712,22 @@ function extractGreenNodeMetadata(green) {
1711
1712
  case "gradient":
1712
1713
  const gradientColors = value.split(",").map((c) => c.trim()).filter((c) => c.startsWith("#"));
1713
1714
  return gradientColors.length > 0 ? { colors: gradientColors } : {};
1715
+ case "table_th":
1716
+ case "table_col": {
1717
+ if (!value) return {};
1718
+ const parts = value.split(/[:,\s]+/).filter(Boolean);
1719
+ const res = {};
1720
+ for (const p of parts) {
1721
+ if (/^\d+$/.test(p)) {
1722
+ res.colspan = parseInt(p, 10);
1723
+ } else if (/^(center|centre|left|right|justify)$/i.test(p)) {
1724
+ res.align = p.toLowerCase() === "centre" ? "center" : p.toLowerCase();
1725
+ } else if (/^#[0-9a-fA-F]{3,8}$/.test(p)) {
1726
+ res.color = p;
1727
+ }
1728
+ }
1729
+ return res;
1730
+ }
1714
1731
  case "notice":
1715
1732
  case "wnotice":
1716
1733
  return value ? { color: value } : {};
@@ -3635,6 +3652,9 @@ var TagRegistry = class {
3635
3652
  { name: "left", kind: "left", label: "Left", category: "layout", isInline: false, isSelfClosing: false, canHaveChildren: true },
3636
3653
  { name: "heading", kind: "heading", label: "Heading", category: "layout", isInline: false, isSelfClosing: false, canHaveChildren: true },
3637
3654
  { name: "notice", kind: "notice", label: "Notice", category: "layout", isInline: false, isSelfClosing: false, canHaveChildren: true },
3655
+ { name: "wnotice", kind: "wnotice", label: "Warning Notice", category: "layout", isInline: false, isSelfClosing: false, canHaveChildren: true },
3656
+ { name: "square", kind: "container", label: "Square Badge", category: "layout", isInline: true, isSelfClosing: false, canHaveChildren: true },
3657
+ { name: "circle", kind: "container", label: "Square Badge", category: "layout", isInline: true, isSelfClosing: false, canHaveChildren: true, isDeprecated: true, deprecatedReplacement: "square" },
3638
3658
  { name: "spacing", kind: "spacing", label: "Spacing", category: "layout", isInline: false, isSelfClosing: true, canHaveChildren: false },
3639
3659
  { name: "empty_line", kind: "empty_line", label: "Empty Line", category: "layout", isInline: false, isSelfClosing: true, canHaveChildren: false },
3640
3660
  // ── Media ──
@@ -5133,11 +5153,39 @@ var HTMLRenderer = class _HTMLRenderer extends Visitor {
5133
5153
  return this.renderTables(node);
5134
5154
  case "table_row":
5135
5155
  return this.tableDepth > 0 ? this.wrapBlock("tr", node) : this.wrapInline("span", node);
5136
- case "table_col":
5137
- return this.tableDepth > 0 ? this.wrapInline("td", node) : this.wrapInline("span", node);
5156
+ case "table_col": {
5157
+ if (this.tableDepth <= 0) return this.wrapInline("span", node);
5158
+ const { cellCount, maxCols, isDirect } = this.getTableContext(node);
5159
+ let colspanAttr = "";
5160
+ if (node.metadata?.colspan) {
5161
+ colspanAttr = ` colspan="${node.metadata.colspan}"`;
5162
+ } else if (cellCount === 1 && maxCols > 1) {
5163
+ colspanAttr = ` colspan="${maxCols}"`;
5164
+ } else if (cellCount < maxCols && maxCols % cellCount === 0) {
5165
+ colspanAttr = ` colspan="${maxCols / cellCount}"`;
5166
+ }
5167
+ const align = node.metadata?.align ? ` style="text-align:${node.metadata.align};"` : "";
5168
+ const td = `<td${this.idAttr(node)}${colspanAttr}${align}>${this.renderChildren(node)}</td>`;
5169
+ return isDirect ? `<tr>${td}</tr>` : td;
5170
+ }
5138
5171
  case "table_th": {
5139
5172
  const content = this.renderChildren(node);
5140
- return this.tableDepth > 0 ? `<th${this.idAttr(node)} class="bb-th"><span class="bb-table-badge">${content}</span></th>` : this.wrapInline("span", node);
5173
+ if (this.tableDepth <= 0) return this.wrapInline("span", node);
5174
+ const { cellCount, maxCols, isDirect } = this.getTableContext(node);
5175
+ let colspanAttr = "";
5176
+ let fullCls = "";
5177
+ if (node.metadata?.colspan) {
5178
+ colspanAttr = ` colspan="${node.metadata.colspan}"`;
5179
+ } else if (cellCount === 1) {
5180
+ colspanAttr = maxCols > 1 ? ` colspan="${maxCols}"` : ' colspan="100"';
5181
+ fullCls = " bb-th-full";
5182
+ } else if (cellCount < maxCols && maxCols % cellCount === 0) {
5183
+ colspanAttr = ` colspan="${maxCols / cellCount}"`;
5184
+ }
5185
+ const alignCls = node.metadata?.align ? ` bb-th-${node.metadata.align}` : "";
5186
+ const alignStyle = node.metadata?.align ? ` style="text-align:${node.metadata.align};"` : "";
5187
+ const th = `<th${this.idAttr(node)}${colspanAttr} class="bb-th${fullCls}${alignCls}"${alignStyle}><span class="bb-table-badge">${content}</span></th>`;
5188
+ return isDirect ? `<tr>${th}</tr>` : th;
5141
5189
  }
5142
5190
  case "gallery":
5143
5191
  return this.renderGallery(node);
@@ -5311,8 +5359,33 @@ var HTMLRenderer = class _HTMLRenderer extends Visitor {
5311
5359
  static CSS_FONT_RE = /^[A-Za-z0-9 ,_-]{1,120}$/;
5312
5360
  /** Characters `escapeHtml` has to rewrite. Non-global on purpose: `test` must not carry `lastIndex`. */
5313
5361
  static HTML_ESCAPE_RE = /[&<>"']/;
5362
+ static BARE_HEX_RE = /^[0-9a-f]{3,8}$/i;
5363
+ static NAMED_COLORS = {
5364
+ black: "#000000",
5365
+ white: "#FFFFFF",
5366
+ red: "#FF4C4C",
5367
+ green: "#2ECC71",
5368
+ blue: "#3498DB",
5369
+ yellow: "#F1C40F",
5370
+ cyan: "#2EE6E2",
5371
+ magenta: "#E056FD",
5372
+ pink: "#FF94C4",
5373
+ purple: "#A972FF",
5374
+ orange: "#FF9F43",
5375
+ amber: "#FFC34D",
5376
+ gray: "#8395A7",
5377
+ grey: "#8395A7",
5378
+ lime: "#10AC84",
5379
+ teal: "#01CBC6",
5380
+ violet: "#5F27CD",
5381
+ gold: "#FFD700"
5382
+ };
5314
5383
  sanitizeColor(raw) {
5315
- const v = raw.trim();
5384
+ let v = raw.trim();
5385
+ if (!v) return null;
5386
+ if (_HTMLRenderer.BARE_HEX_RE.test(v) && (v.length === 3 || v.length === 4 || v.length === 6 || v.length === 8)) {
5387
+ v = "#" + v;
5388
+ }
5316
5389
  return _HTMLRenderer.CSS_COLOR_RE.test(v) ? v : null;
5317
5390
  }
5318
5391
  sanitizeFontSize(raw) {
@@ -5448,8 +5521,12 @@ var HTMLRenderer = class _HTMLRenderer extends Visitor {
5448
5521
  return `<audio${this.idAttr(node)} controls src="${this.escapeHtml(src)}" class="bb-audio"></audio>`;
5449
5522
  }
5450
5523
  hexToRgba(hex, alpha) {
5451
- if (!hex.startsWith("#")) return hex;
5452
- const t = hex.replace("#", "");
5524
+ let clean = hex.trim().toLowerCase();
5525
+ if (_HTMLRenderer.NAMED_COLORS[clean]) {
5526
+ clean = _HTMLRenderer.NAMED_COLORS[clean];
5527
+ }
5528
+ if (!clean.startsWith("#")) return clean;
5529
+ const t = clean.replace("#", "");
5453
5530
  const full = t.length <= 4 ? t.split("").map((c) => c + c).join("") : t;
5454
5531
  const r = parseInt(full.slice(0, 2), 16) || 0;
5455
5532
  const g = parseInt(full.slice(2, 4), 16) || 0;
@@ -5482,6 +5559,22 @@ var HTMLRenderer = class _HTMLRenderer extends Visitor {
5482
5559
  const accent = this.boxAccentStyle(node, "table");
5483
5560
  return `<div${this.idAttr(node)} class="bb-table-frame"${accent}><table class="${tableClasses}"><tbody>${content}</tbody></table></div>`;
5484
5561
  }
5562
+ getTableContext(node) {
5563
+ const parent = node.parent;
5564
+ const isDirect = parent?.kind === "tables";
5565
+ const tableNode = isDirect ? parent : parent?.parent?.kind === "tables" ? parent.parent : void 0;
5566
+ const cellCount = parent?.children ? parent.children.filter((c) => c.kind === "table_th" || c.kind === "table_col").length : 1;
5567
+ let maxCols = cellCount;
5568
+ if (tableNode) {
5569
+ for (const row of tableNode.children) {
5570
+ if (row.kind === "table_row") {
5571
+ const count = row.children.filter((c) => c.kind === "table_th" || c.kind === "table_col").length;
5572
+ if (count > maxCols) maxCols = count;
5573
+ }
5574
+ }
5575
+ }
5576
+ return { cellCount, maxCols, isDirect };
5577
+ }
5485
5578
  renderGallery(node) {
5486
5579
  const content = this.renderChildren(node);
5487
5580
  return `<div${this.idAttr(node)} class="bb-gallery">${content}</div>`;
@@ -5627,8 +5720,14 @@ var HTMLRenderer = class _HTMLRenderer extends Visitor {
5627
5720
  }
5628
5721
  case "middle":
5629
5722
  return `<div${idAttr} class="bb-middle">${content}</div>`;
5630
- case "circle":
5631
- return `<div${idAttr} class="bb-circle">${content}</div>`;
5723
+ case "square":
5724
+ case "circle": {
5725
+ const accent = this.sanitizeColor(param);
5726
+ const border = accent ? this.hexToRgba(accent, 0.35) : "";
5727
+ const bg = accent ? this.hexToRgba(accent, 0.08) : "";
5728
+ const style = accent ? ` style="--square-accent:${accent};--square-border:${border};--square-bg:${bg};"` : "";
5729
+ return `<div${idAttr} class="bb-square bb-cut-panel"${style}>${content}</div>`;
5730
+ }
5632
5731
  case "card":
5633
5732
  case "glass": {
5634
5733
  const accent = this.sanitizeColor(param);
@@ -5740,7 +5839,10 @@ var HTMLRenderer = class _HTMLRenderer extends Visitor {
5740
5839
  */
5741
5840
  boxAccentStyle(node, suffix = "box") {
5742
5841
  const color = this.sanitizeColor(String(node.metadata?.color ?? ""));
5743
- return color ? ` style="--${suffix}-accent:${color};"` : "";
5842
+ if (!color) return "";
5843
+ const border = this.hexToRgba(color, 0.35);
5844
+ const bg = this.hexToRgba(color, 0.08);
5845
+ return ` style="--${suffix}-accent:${color};--${suffix}-border:${border};--${suffix}-bg:${bg};"`;
5744
5846
  }
5745
5847
  renderList(node) {
5746
5848
  const attrs = this.extractValue(node);
package/dist/index.mjs CHANGED
@@ -1546,6 +1546,7 @@ var LYNE_LEGACY_ALIASES = {
1546
1546
  "flex": "container",
1547
1547
  "grid": "container",
1548
1548
  "middle": "container",
1549
+ "square": "container",
1549
1550
  "circle": "container",
1550
1551
  "card": "container",
1551
1552
  "glass": "container",
@@ -1709,6 +1710,22 @@ function extractGreenNodeMetadata(green) {
1709
1710
  case "gradient":
1710
1711
  const gradientColors = value.split(",").map((c) => c.trim()).filter((c) => c.startsWith("#"));
1711
1712
  return gradientColors.length > 0 ? { colors: gradientColors } : {};
1713
+ case "table_th":
1714
+ case "table_col": {
1715
+ if (!value) return {};
1716
+ const parts = value.split(/[:,\s]+/).filter(Boolean);
1717
+ const res = {};
1718
+ for (const p of parts) {
1719
+ if (/^\d+$/.test(p)) {
1720
+ res.colspan = parseInt(p, 10);
1721
+ } else if (/^(center|centre|left|right|justify)$/i.test(p)) {
1722
+ res.align = p.toLowerCase() === "centre" ? "center" : p.toLowerCase();
1723
+ } else if (/^#[0-9a-fA-F]{3,8}$/.test(p)) {
1724
+ res.color = p;
1725
+ }
1726
+ }
1727
+ return res;
1728
+ }
1712
1729
  case "notice":
1713
1730
  case "wnotice":
1714
1731
  return value ? { color: value } : {};
@@ -3633,6 +3650,9 @@ var TagRegistry = class {
3633
3650
  { name: "left", kind: "left", label: "Left", category: "layout", isInline: false, isSelfClosing: false, canHaveChildren: true },
3634
3651
  { name: "heading", kind: "heading", label: "Heading", category: "layout", isInline: false, isSelfClosing: false, canHaveChildren: true },
3635
3652
  { name: "notice", kind: "notice", label: "Notice", category: "layout", isInline: false, isSelfClosing: false, canHaveChildren: true },
3653
+ { name: "wnotice", kind: "wnotice", label: "Warning Notice", category: "layout", isInline: false, isSelfClosing: false, canHaveChildren: true },
3654
+ { name: "square", kind: "container", label: "Square Badge", category: "layout", isInline: true, isSelfClosing: false, canHaveChildren: true },
3655
+ { name: "circle", kind: "container", label: "Square Badge", category: "layout", isInline: true, isSelfClosing: false, canHaveChildren: true, isDeprecated: true, deprecatedReplacement: "square" },
3636
3656
  { name: "spacing", kind: "spacing", label: "Spacing", category: "layout", isInline: false, isSelfClosing: true, canHaveChildren: false },
3637
3657
  { name: "empty_line", kind: "empty_line", label: "Empty Line", category: "layout", isInline: false, isSelfClosing: true, canHaveChildren: false },
3638
3658
  // ── Media ──
@@ -5131,11 +5151,39 @@ var HTMLRenderer = class _HTMLRenderer extends Visitor {
5131
5151
  return this.renderTables(node);
5132
5152
  case "table_row":
5133
5153
  return this.tableDepth > 0 ? this.wrapBlock("tr", node) : this.wrapInline("span", node);
5134
- case "table_col":
5135
- return this.tableDepth > 0 ? this.wrapInline("td", node) : this.wrapInline("span", node);
5154
+ case "table_col": {
5155
+ if (this.tableDepth <= 0) return this.wrapInline("span", node);
5156
+ const { cellCount, maxCols, isDirect } = this.getTableContext(node);
5157
+ let colspanAttr = "";
5158
+ if (node.metadata?.colspan) {
5159
+ colspanAttr = ` colspan="${node.metadata.colspan}"`;
5160
+ } else if (cellCount === 1 && maxCols > 1) {
5161
+ colspanAttr = ` colspan="${maxCols}"`;
5162
+ } else if (cellCount < maxCols && maxCols % cellCount === 0) {
5163
+ colspanAttr = ` colspan="${maxCols / cellCount}"`;
5164
+ }
5165
+ const align = node.metadata?.align ? ` style="text-align:${node.metadata.align};"` : "";
5166
+ const td = `<td${this.idAttr(node)}${colspanAttr}${align}>${this.renderChildren(node)}</td>`;
5167
+ return isDirect ? `<tr>${td}</tr>` : td;
5168
+ }
5136
5169
  case "table_th": {
5137
5170
  const content = this.renderChildren(node);
5138
- return this.tableDepth > 0 ? `<th${this.idAttr(node)} class="bb-th"><span class="bb-table-badge">${content}</span></th>` : this.wrapInline("span", node);
5171
+ if (this.tableDepth <= 0) return this.wrapInline("span", node);
5172
+ const { cellCount, maxCols, isDirect } = this.getTableContext(node);
5173
+ let colspanAttr = "";
5174
+ let fullCls = "";
5175
+ if (node.metadata?.colspan) {
5176
+ colspanAttr = ` colspan="${node.metadata.colspan}"`;
5177
+ } else if (cellCount === 1) {
5178
+ colspanAttr = maxCols > 1 ? ` colspan="${maxCols}"` : ' colspan="100"';
5179
+ fullCls = " bb-th-full";
5180
+ } else if (cellCount < maxCols && maxCols % cellCount === 0) {
5181
+ colspanAttr = ` colspan="${maxCols / cellCount}"`;
5182
+ }
5183
+ const alignCls = node.metadata?.align ? ` bb-th-${node.metadata.align}` : "";
5184
+ const alignStyle = node.metadata?.align ? ` style="text-align:${node.metadata.align};"` : "";
5185
+ const th = `<th${this.idAttr(node)}${colspanAttr} class="bb-th${fullCls}${alignCls}"${alignStyle}><span class="bb-table-badge">${content}</span></th>`;
5186
+ return isDirect ? `<tr>${th}</tr>` : th;
5139
5187
  }
5140
5188
  case "gallery":
5141
5189
  return this.renderGallery(node);
@@ -5309,8 +5357,33 @@ var HTMLRenderer = class _HTMLRenderer extends Visitor {
5309
5357
  static CSS_FONT_RE = /^[A-Za-z0-9 ,_-]{1,120}$/;
5310
5358
  /** Characters `escapeHtml` has to rewrite. Non-global on purpose: `test` must not carry `lastIndex`. */
5311
5359
  static HTML_ESCAPE_RE = /[&<>"']/;
5360
+ static BARE_HEX_RE = /^[0-9a-f]{3,8}$/i;
5361
+ static NAMED_COLORS = {
5362
+ black: "#000000",
5363
+ white: "#FFFFFF",
5364
+ red: "#FF4C4C",
5365
+ green: "#2ECC71",
5366
+ blue: "#3498DB",
5367
+ yellow: "#F1C40F",
5368
+ cyan: "#2EE6E2",
5369
+ magenta: "#E056FD",
5370
+ pink: "#FF94C4",
5371
+ purple: "#A972FF",
5372
+ orange: "#FF9F43",
5373
+ amber: "#FFC34D",
5374
+ gray: "#8395A7",
5375
+ grey: "#8395A7",
5376
+ lime: "#10AC84",
5377
+ teal: "#01CBC6",
5378
+ violet: "#5F27CD",
5379
+ gold: "#FFD700"
5380
+ };
5312
5381
  sanitizeColor(raw) {
5313
- const v = raw.trim();
5382
+ let v = raw.trim();
5383
+ if (!v) return null;
5384
+ if (_HTMLRenderer.BARE_HEX_RE.test(v) && (v.length === 3 || v.length === 4 || v.length === 6 || v.length === 8)) {
5385
+ v = "#" + v;
5386
+ }
5314
5387
  return _HTMLRenderer.CSS_COLOR_RE.test(v) ? v : null;
5315
5388
  }
5316
5389
  sanitizeFontSize(raw) {
@@ -5446,8 +5519,12 @@ var HTMLRenderer = class _HTMLRenderer extends Visitor {
5446
5519
  return `<audio${this.idAttr(node)} controls src="${this.escapeHtml(src)}" class="bb-audio"></audio>`;
5447
5520
  }
5448
5521
  hexToRgba(hex, alpha) {
5449
- if (!hex.startsWith("#")) return hex;
5450
- const t = hex.replace("#", "");
5522
+ let clean = hex.trim().toLowerCase();
5523
+ if (_HTMLRenderer.NAMED_COLORS[clean]) {
5524
+ clean = _HTMLRenderer.NAMED_COLORS[clean];
5525
+ }
5526
+ if (!clean.startsWith("#")) return clean;
5527
+ const t = clean.replace("#", "");
5451
5528
  const full = t.length <= 4 ? t.split("").map((c) => c + c).join("") : t;
5452
5529
  const r = parseInt(full.slice(0, 2), 16) || 0;
5453
5530
  const g = parseInt(full.slice(2, 4), 16) || 0;
@@ -5480,6 +5557,22 @@ var HTMLRenderer = class _HTMLRenderer extends Visitor {
5480
5557
  const accent = this.boxAccentStyle(node, "table");
5481
5558
  return `<div${this.idAttr(node)} class="bb-table-frame"${accent}><table class="${tableClasses}"><tbody>${content}</tbody></table></div>`;
5482
5559
  }
5560
+ getTableContext(node) {
5561
+ const parent = node.parent;
5562
+ const isDirect = parent?.kind === "tables";
5563
+ const tableNode = isDirect ? parent : parent?.parent?.kind === "tables" ? parent.parent : void 0;
5564
+ const cellCount = parent?.children ? parent.children.filter((c) => c.kind === "table_th" || c.kind === "table_col").length : 1;
5565
+ let maxCols = cellCount;
5566
+ if (tableNode) {
5567
+ for (const row of tableNode.children) {
5568
+ if (row.kind === "table_row") {
5569
+ const count = row.children.filter((c) => c.kind === "table_th" || c.kind === "table_col").length;
5570
+ if (count > maxCols) maxCols = count;
5571
+ }
5572
+ }
5573
+ }
5574
+ return { cellCount, maxCols, isDirect };
5575
+ }
5483
5576
  renderGallery(node) {
5484
5577
  const content = this.renderChildren(node);
5485
5578
  return `<div${this.idAttr(node)} class="bb-gallery">${content}</div>`;
@@ -5625,8 +5718,14 @@ var HTMLRenderer = class _HTMLRenderer extends Visitor {
5625
5718
  }
5626
5719
  case "middle":
5627
5720
  return `<div${idAttr} class="bb-middle">${content}</div>`;
5628
- case "circle":
5629
- return `<div${idAttr} class="bb-circle">${content}</div>`;
5721
+ case "square":
5722
+ case "circle": {
5723
+ const accent = this.sanitizeColor(param);
5724
+ const border = accent ? this.hexToRgba(accent, 0.35) : "";
5725
+ const bg = accent ? this.hexToRgba(accent, 0.08) : "";
5726
+ const style = accent ? ` style="--square-accent:${accent};--square-border:${border};--square-bg:${bg};"` : "";
5727
+ return `<div${idAttr} class="bb-square bb-cut-panel"${style}>${content}</div>`;
5728
+ }
5630
5729
  case "card":
5631
5730
  case "glass": {
5632
5731
  const accent = this.sanitizeColor(param);
@@ -5738,7 +5837,10 @@ var HTMLRenderer = class _HTMLRenderer extends Visitor {
5738
5837
  */
5739
5838
  boxAccentStyle(node, suffix = "box") {
5740
5839
  const color = this.sanitizeColor(String(node.metadata?.color ?? ""));
5741
- return color ? ` style="--${suffix}-accent:${color};"` : "";
5840
+ if (!color) return "";
5841
+ const border = this.hexToRgba(color, 0.35);
5842
+ const bg = this.hexToRgba(color, 0.08);
5843
+ return ` style="--${suffix}-accent:${color};--${suffix}-border:${border};--${suffix}-bg:${bg};"`;
5742
5844
  }
5743
5845
  renderList(node) {
5744
5846
  const attrs = this.extractValue(node);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@miliastry/quasar",
3
- "version": "1.0.4",
3
+ "version": "1.0.6",
4
4
  "description": "Quasar Document Engine - Advanced BBCode/Markdown/HTML AST Engine",
5
5
  "main": "src/index.ts",
6
6
  "types": "src/index.ts",
@@ -188,6 +188,7 @@ const LYNE_LEGACY_ALIASES: Record<string, NodeKind> = {
188
188
  'flex': 'container',
189
189
  'grid': 'container',
190
190
  'middle': 'container',
191
+ 'square': 'container',
191
192
  'circle': 'container',
192
193
  'card': 'container',
193
194
  'glass': 'container',
@@ -441,6 +442,22 @@ export function extractGreenNodeMetadata(green: GreenNode): Record<string, unkno
441
442
  // Parse "=#ff0000,#00ff00" → { colors: ['#FF0000', '#00FF00'] }
442
443
  const gradientColors = value.split(',').map(c => c.trim()).filter(c => c.startsWith('#'))
443
444
  return gradientColors.length > 0 ? { colors: gradientColors } : {}
445
+ case 'table_th':
446
+ case 'table_col': {
447
+ if (!value) return {}
448
+ const parts = value.split(/[:,\s]+/).filter(Boolean)
449
+ const res: Record<string, any> = {}
450
+ for (const p of parts) {
451
+ if (/^\d+$/.test(p)) {
452
+ res.colspan = parseInt(p, 10)
453
+ } else if (/^(center|centre|left|right|justify)$/i.test(p)) {
454
+ res.align = p.toLowerCase() === 'centre' ? 'center' : p.toLowerCase()
455
+ } else if (/^#[0-9a-fA-F]{3,8}$/.test(p)) {
456
+ res.color = p
457
+ }
458
+ }
459
+ return res
460
+ }
444
461
  case 'notice':
445
462
  case 'wnotice': return value ? { color: value } : {}
446
463
  case 'tables':
@@ -464,6 +464,9 @@ export class TagRegistry {
464
464
  { name: 'left', kind: 'left', label: 'Left', category: 'layout', isInline: false, isSelfClosing: false, canHaveChildren: true },
465
465
  { name: 'heading', kind: 'heading', label: 'Heading', category: 'layout', isInline: false, isSelfClosing: false, canHaveChildren: true },
466
466
  { name: 'notice', kind: 'notice', label: 'Notice', category: 'layout', isInline: false, isSelfClosing: false, canHaveChildren: true },
467
+ { name: 'wnotice', kind: 'wnotice', label: 'Warning Notice', category: 'layout', isInline: false, isSelfClosing: false, canHaveChildren: true },
468
+ { name: 'square', kind: 'container', label: 'Square Badge', category: 'layout', isInline: true, isSelfClosing: false, canHaveChildren: true },
469
+ { name: 'circle', kind: 'container', label: 'Square Badge', category: 'layout', isInline: true, isSelfClosing: false, canHaveChildren: true, isDeprecated: true, deprecatedReplacement: 'square' },
467
470
  { name: 'spacing', kind: 'spacing', label: 'Spacing', category: 'layout', isInline: false, isSelfClosing: true, canHaveChildren: false },
468
471
  { name: 'empty_line', kind: 'empty_line', label: 'Empty Line', category: 'layout', isInline: false, isSelfClosing: true, canHaveChildren: false },
469
472
 
@@ -110,7 +110,7 @@ describe('Lyne Mode & Dialect Isolation', () => {
110
110
 
111
111
  const html = doc.toHTML()
112
112
  expect(html).toContain('class="bb-table bb-table-striped bb-table-borders"')
113
- expect(html).toContain('class="bb-th"')
113
+ expect(html).toContain('bb-th')
114
114
  expect(html).toContain('class="bb-columns" style="column-count:3;"')
115
115
  expect(html).toContain('class="bb-gallery"')
116
116
  expect(html).toContain('✦ ✦ ✦')
@@ -304,12 +304,39 @@ export class HTMLRenderer extends Visitor<string> {
304
304
  case 'align': return this.renderAlign(node)
305
305
  case 'tables': return this.renderTables(node)
306
306
  case 'table_row': return this.tableDepth > 0 ? this.wrapBlock('tr', node) : this.wrapInline('span', node)
307
- case 'table_col': return this.tableDepth > 0 ? this.wrapInline('td', node) : this.wrapInline('span', node)
307
+ case 'table_col': {
308
+ if (this.tableDepth <= 0) return this.wrapInline('span', node)
309
+ const { cellCount, maxCols, isDirect } = this.getTableContext(node)
310
+ let colspanAttr = ''
311
+ if (node.metadata?.colspan) {
312
+ colspanAttr = ` colspan="${node.metadata.colspan}"`
313
+ } else if (cellCount === 1 && maxCols > 1) {
314
+ colspanAttr = ` colspan="${maxCols}"`
315
+ } else if (cellCount < maxCols && maxCols % cellCount === 0) {
316
+ colspanAttr = ` colspan="${maxCols / cellCount}"`
317
+ }
318
+ const align = node.metadata?.align ? ` style="text-align:${node.metadata.align};"` : ''
319
+ const td = `<td${this.idAttr(node)}${colspanAttr}${align}>${this.renderChildren(node)}</td>`
320
+ return isDirect ? `<tr>${td}</tr>` : td
321
+ }
308
322
  case 'table_th': {
309
323
  const content = this.renderChildren(node)
310
- return this.tableDepth > 0
311
- ? `<th${this.idAttr(node)} class="bb-th"><span class="bb-table-badge">${content}</span></th>`
312
- : this.wrapInline('span', node)
324
+ if (this.tableDepth <= 0) return this.wrapInline('span', node)
325
+ const { cellCount, maxCols, isDirect } = this.getTableContext(node)
326
+ let colspanAttr = ''
327
+ let fullCls = ''
328
+ if (node.metadata?.colspan) {
329
+ colspanAttr = ` colspan="${node.metadata.colspan}"`
330
+ } else if (cellCount === 1) {
331
+ colspanAttr = maxCols > 1 ? ` colspan="${maxCols}"` : ' colspan="100"'
332
+ fullCls = ' bb-th-full'
333
+ } else if (cellCount < maxCols && maxCols % cellCount === 0) {
334
+ colspanAttr = ` colspan="${maxCols / cellCount}"`
335
+ }
336
+ const alignCls = node.metadata?.align ? ` bb-th-${node.metadata.align}` : ''
337
+ const alignStyle = node.metadata?.align ? ` style="text-align:${node.metadata.align};"` : ''
338
+ const th = `<th${this.idAttr(node)}${colspanAttr} class="bb-th${fullCls}${alignCls}"${alignStyle}><span class="bb-table-badge">${content}</span></th>`
339
+ return isDirect ? `<tr>${th}</tr>` : th
313
340
  }
314
341
  case 'gallery': return this.renderGallery(node)
315
342
  case 'columns': return this.renderColumns(node)
@@ -475,8 +502,35 @@ export class HTMLRenderer extends Visitor<string> {
475
502
  /** Characters `escapeHtml` has to rewrite. Non-global on purpose: `test` must not carry `lastIndex`. */
476
503
  private static readonly HTML_ESCAPE_RE = /[&<>"']/
477
504
 
505
+ private static readonly BARE_HEX_RE = /^[0-9a-f]{3,8}$/i
506
+
507
+ private static readonly NAMED_COLORS: Record<string, string> = {
508
+ black: '#000000',
509
+ white: '#FFFFFF',
510
+ red: '#FF4C4C',
511
+ green: '#2ECC71',
512
+ blue: '#3498DB',
513
+ yellow: '#F1C40F',
514
+ cyan: '#2EE6E2',
515
+ magenta: '#E056FD',
516
+ pink: '#FF94C4',
517
+ purple: '#A972FF',
518
+ orange: '#FF9F43',
519
+ amber: '#FFC34D',
520
+ gray: '#8395A7',
521
+ grey: '#8395A7',
522
+ lime: '#10AC84',
523
+ teal: '#01CBC6',
524
+ violet: '#5F27CD',
525
+ gold: '#FFD700',
526
+ }
527
+
478
528
  private sanitizeColor(raw: string): string | null {
479
- const v = raw.trim()
529
+ let v = raw.trim()
530
+ if (!v) return null
531
+ if (HTMLRenderer.BARE_HEX_RE.test(v) && (v.length === 3 || v.length === 4 || v.length === 6 || v.length === 8)) {
532
+ v = '#' + v
533
+ }
480
534
  return HTMLRenderer.CSS_COLOR_RE.test(v) ? v : null
481
535
  }
482
536
 
@@ -637,8 +691,12 @@ export class HTMLRenderer extends Visitor<string> {
637
691
  }
638
692
 
639
693
  private hexToRgba(hex: string, alpha: number): string {
640
- if (!hex.startsWith('#')) return hex
641
- const t = hex.replace('#', '')
694
+ let clean = hex.trim().toLowerCase()
695
+ if (HTMLRenderer.NAMED_COLORS[clean]) {
696
+ clean = HTMLRenderer.NAMED_COLORS[clean]
697
+ }
698
+ if (!clean.startsWith('#')) return clean
699
+ const t = clean.replace('#', '')
642
700
  const full = t.length <= 4 ? t.split('').map(c => c + c).join('') : t
643
701
  const r = parseInt(full.slice(0, 2), 16) || 0
644
702
  const g = parseInt(full.slice(2, 4), 16) || 0
@@ -679,6 +737,26 @@ export class HTMLRenderer extends Visitor<string> {
679
737
  return `<div${this.idAttr(node)} class="bb-table-frame"${accent}><table class="${tableClasses}"><tbody>${content}</tbody></table></div>`
680
738
  }
681
739
 
740
+ private getTableContext(node: RedNode): { cellCount: number; maxCols: number; isDirect: boolean } {
741
+ const parent = node.parent
742
+ const isDirect = parent?.kind === 'tables'
743
+ const tableNode = isDirect ? parent : (parent?.parent?.kind === 'tables' ? parent.parent : undefined)
744
+ const cellCount = parent?.children
745
+ ? parent.children.filter(c => c.kind === 'table_th' || c.kind === 'table_col').length
746
+ : 1
747
+
748
+ let maxCols = cellCount
749
+ if (tableNode) {
750
+ for (const row of tableNode.children) {
751
+ if (row.kind === 'table_row') {
752
+ const count = row.children.filter(c => c.kind === 'table_th' || c.kind === 'table_col').length
753
+ if (count > maxCols) maxCols = count
754
+ }
755
+ }
756
+ }
757
+ return { cellCount, maxCols, isDirect }
758
+ }
759
+
682
760
  private renderGallery(node: RedNode): string {
683
761
  const content = this.renderChildren(node)
684
762
  return `<div${this.idAttr(node)} class="bb-gallery">${content}</div>`
@@ -824,8 +902,14 @@ export class HTMLRenderer extends Visitor<string> {
824
902
  }
825
903
  case 'middle':
826
904
  return `<div${idAttr} class="bb-middle">${content}</div>`
827
- case 'circle':
828
- return `<div${idAttr} class="bb-circle">${content}</div>`
905
+ case 'square':
906
+ case 'circle': {
907
+ const accent = this.sanitizeColor(param)
908
+ const border = accent ? this.hexToRgba(accent, 0.35) : ''
909
+ const bg = accent ? this.hexToRgba(accent, 0.08) : ''
910
+ const style = accent ? ` style="--square-accent:${accent};--square-border:${border};--square-bg:${bg};"` : ''
911
+ return `<div${idAttr} class="bb-square bb-cut-panel"${style}>${content}</div>`
912
+ }
829
913
  case 'card':
830
914
  case 'glass': {
831
915
  // `[card=#hex]` / `[container=glass:#hex]`: el color se pasa como
@@ -942,7 +1026,10 @@ export class HTMLRenderer extends Visitor<string> {
942
1026
  */
943
1027
  private boxAccentStyle(node: RedNode, suffix: 'box' | 'table' | 'columns' = 'box'): string {
944
1028
  const color = this.sanitizeColor(String(node.metadata?.color ?? ''))
945
- return color ? ` style="--${suffix}-accent:${color};"` : ''
1029
+ if (!color) return ''
1030
+ const border = this.hexToRgba(color, 0.35)
1031
+ const bg = this.hexToRgba(color, 0.08)
1032
+ return ` style="--${suffix}-accent:${color};--${suffix}-border:${border};--${suffix}-bg:${bg};"`
946
1033
  }
947
1034
 
948
1035
  private renderList(node: RedNode): string {
@@ -249,8 +249,8 @@
249
249
  * del autor ([boxw=Title:#hex]) si lo hay; si no, el hairline del tema. */
250
250
  .bbcode-preview-lyne details.boxw,
251
251
  .bbcode-preview.theme-lyne details.boxw {
252
- background: rgba(11, 16, 36, 0.5) !important;
253
- border: 1px solid var(--box-accent, var(--card-accent, var(--glass-accent, var(--color-hairline, rgba(255, 255, 255, 0.12))))) !important;
252
+ background: var(--box-bg, rgba(11, 16, 36, 0.5)) !important;
253
+ border: 1px solid var(--box-border, var(--box-accent, var(--card-accent, var(--glass-accent, var(--color-hairline, rgba(255, 255, 255, 0.12)))))) !important;
254
254
  border-radius: 0 !important;
255
255
  clip-path: polygon(8px 0, 100% 0, 100% calc(100% - 8px), calc(100% - 8px) 100%, 0 100%, 0 8px) !important;
256
256
  padding: 0 !important;
@@ -331,8 +331,8 @@
331
331
  width: 7px !important;
332
332
  height: 7px !important;
333
333
  flex: 0 0 7px !important;
334
- border-right: 1.5px solid currentColor !important;
335
- border-bottom: 1.5px solid currentColor !important;
334
+ border-right: 1px solid currentColor !important;
335
+ border-bottom: 1px solid currentColor !important;
336
336
  transform: rotate(-45deg) !important;
337
337
  transition: transform 0.15s ease !important;
338
338
  }
@@ -360,7 +360,7 @@
360
360
 
361
361
  .bbcode-preview-lyne details.boxw[open] > summary,
362
362
  .bbcode-preview.theme-lyne details.boxw[open] > summary {
363
- border-bottom: 1px solid var(--box-accent, var(--card-accent, var(--glass-accent, var(--color-hairline, rgba(255, 255, 255, 0.12))))) !important;
363
+ border-bottom: 1px solid var(--box-border, var(--box-accent, var(--card-accent, var(--glass-accent, var(--color-hairline, rgba(255, 255, 255, 0.12)))))) !important;
364
364
  }
365
365
 
366
366
  .bbcode-preview-lyne details[open] > summary::before,
@@ -370,7 +370,8 @@
370
370
 
371
371
  .bbcode-preview-lyne details > summary:hover,
372
372
  .bbcode-preview.theme-lyne details > summary:hover {
373
- color: var(--color-accent-bright, #68FFF8) !important;
373
+ color: var(--box-accent, var(--card-accent, var(--glass-accent, var(--color-accent-bright, #68FFF8)))) !important;
374
+ filter: brightness(1.25) !important;
374
375
  }
375
376
 
376
377
  /* ─── Lists & Markers ───────────────────────────────────────────────────── */
@@ -469,6 +470,7 @@
469
470
  .bb-table {
470
471
  width: 100% !important;
471
472
  min-width: 380px !important;
473
+ table-layout: fixed !important;
472
474
  border-collapse: separate !important;
473
475
  border-spacing: 0 !important;
474
476
  margin: 0 !important;
@@ -518,6 +520,64 @@
518
520
  line-height: 1.3 !important;
519
521
  text-transform: uppercase !important;
520
522
  padding: 8px 10px !important;
523
+ text-align: left !important;
524
+ }
525
+
526
+ .bb-table .bb-th.bb-th-full {
527
+ width: 100% !important;
528
+ }
529
+
530
+ /* Table header alignments */
531
+ .bb-table .bb-th.bb-th-left,
532
+ .bb-table .bb-th:has(.bb-left),
533
+ .bb-table .bb-th:has([style*="text-align:left"]),
534
+ .bb-table .bb-th:has([style*="text-align: left"]),
535
+ .bb-left .bb-table .bb-th {
536
+ text-align: left !important;
537
+ }
538
+
539
+ .bb-table .bb-th.bb-th-left .bb-table-badge,
540
+ .bb-table .bb-th:has(.bb-left) .bb-table-badge,
541
+ .bb-table .bb-th:has([style*="text-align:left"]) .bb-table-badge,
542
+ .bb-table .bb-th:has([style*="text-align: left"]) .bb-table-badge,
543
+ .bb-left .bb-table .bb-th .bb-table-badge {
544
+ margin-right: auto !important;
545
+ margin-left: 0 !important;
546
+ }
547
+
548
+ .bb-table .bb-th.bb-th-centered,
549
+ .bb-table .bb-th.bb-th-center,
550
+ .bb-table .bb-th:has(.bb-centre),
551
+ .bb-table .bb-th:has([style*="text-align:center"]),
552
+ .bb-table .bb-th:has([style*="text-align: center"]),
553
+ .bb-centre .bb-table .bb-th {
554
+ text-align: center !important;
555
+ }
556
+
557
+ .bb-table .bb-th.bb-th-centered .bb-table-badge,
558
+ .bb-table .bb-th.bb-th-center .bb-table-badge,
559
+ .bb-table .bb-th:has(.bb-centre) .bb-table-badge,
560
+ .bb-table .bb-th:has([style*="text-align:center"]) .bb-table-badge,
561
+ .bb-table .bb-th:has([style*="text-align: center"]) .bb-table-badge,
562
+ .bb-centre .bb-table .bb-th .bb-table-badge {
563
+ margin: 0 auto !important;
564
+ }
565
+
566
+ .bb-table .bb-th.bb-th-right,
567
+ .bb-table .bb-th:has(.bb-right),
568
+ .bb-table .bb-th:has([style*="text-align:right"]),
569
+ .bb-table .bb-th:has([style*="text-align: right"]),
570
+ .bb-right .bb-table .bb-th {
571
+ text-align: right !important;
572
+ }
573
+
574
+ .bb-table .bb-th.bb-th-right .bb-table-badge,
575
+ .bb-table .bb-th:has(.bb-right) .bb-table-badge,
576
+ .bb-table .bb-th:has([style*="text-align:right"]) .bb-table-badge,
577
+ .bb-table .bb-th:has([style*="text-align: right"]) .bb-table-badge,
578
+ .bb-right .bb-table .bb-th .bb-table-badge {
579
+ margin-left: auto !important;
580
+ margin-right: 0 !important;
521
581
  }
522
582
 
523
583
  .bb-table-badge {
@@ -610,7 +670,7 @@
610
670
  border: 0 !important;
611
671
  height: 1px !important;
612
672
  background: linear-gradient(90deg, transparent, var(--color-accent, #2EE6E2), transparent) !important;
613
- margin: 0 !important;
673
+ margin: 12px 0 !important;
614
674
  text-align: center !important;
615
675
  color: var(--color-accent, #2EE6E2) !important;
616
676
  font-family: var(--font-numeric, monospace) !important;
@@ -733,7 +793,7 @@
733
793
  .bb-neon-box {
734
794
  padding: 16px !important;
735
795
  margin: 0 !important;
736
- border: 2px solid var(--neon-color, var(--color-accent, #2EE6E2)) !important;
796
+ border: 1px solid var(--neon-color, var(--color-accent, #2EE6E2)) !important;
737
797
  background: color-mix(in srgb, var(--neon-color, var(--color-accent, #2EE6E2)) 4%, rgba(7, 10, 23, 0.55)) !important;
738
798
  border-radius: 0 !important;
739
799
  box-shadow: none !important;
@@ -758,20 +818,26 @@
758
818
  align-items: center !important;
759
819
  }
760
820
 
761
- /* Circle: replica el .bbCircle original de Lyne (Main Bridge/line/web/
762
- * components/bbcode.module.css). aspect-ratio:1 + centrado convierten el div
763
- * en un círculo real con el contenido al centro; fondo y borde lo pintan como
764
- * badge. clip-path:none evita que herede los cortes de esquina de los paneles. */
821
+ /* Square: cuadradito badge con las muescas angulares características de Lyne.
822
+ * aspect-ratio: 1/1, centrado, borde hairline y corte angular de esquina. */
823
+ .bb-square,
765
824
  .bb-circle {
766
825
  display: inline-flex !important;
767
826
  align-items: center !important;
768
827
  justify-content: center !important;
769
- aspect-ratio: 1 !important;
770
- border-radius: 50% !important;
828
+ aspect-ratio: 1 / 1 !important;
829
+ min-width: 1.85em !important;
830
+ min-height: 1.85em !important;
831
+ padding: 0.2em 0.35em !important;
832
+ box-sizing: border-box !important;
833
+ border-radius: 0 !important;
771
834
  overflow: hidden !important;
772
- background: rgb(11 16 36 / 0.5) !important;
773
- border: 1px solid var(--color-hairline, rgba(255, 255, 255, 0.12)) !important;
774
- clip-path: none !important;
835
+ background: var(--square-bg, rgb(11 16 36 / 0.5)) !important;
836
+ border: 1px solid var(--square-border, var(--square-accent, var(--color-hairline, rgba(255, 255, 255, 0.12)))) !important;
837
+ clip-path: polygon(4px 0, 100% 0, 100% calc(100% - 4px), calc(100% - 4px) 100%, 0 100%, 0 4px) !important;
838
+ text-align: center !important;
839
+ line-height: 1 !important;
840
+ vertical-align: middle !important;
775
841
  }
776
842
 
777
843
  /* Stack: replica el .bbStack original de Lyne (columna flex con gap).