juxscript 1.1.194 → 1.1.196
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.
- package/lib/components/dataframe.d.ts.map +1 -1
- package/lib/components/dataframe.js +138 -67
- package/lib/components/dataframe.ts +150 -70
- package/lib/styles/shadcn.css +30 -32
- package/package.json +1 -1
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"dataframe.d.ts","sourceRoot":"","sources":["dataframe.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,aAAa,EAAE,SAAS,EAAE,MAAM,yBAAyB,CAAC;AACnE,OAAO,EAAE,SAAS,EAAE,MAAM,yBAAyB,CAAC;AACpD,OAAO,EAAE,aAAa,EAAE,MAAM,6BAA6B,CAAC;AAC5D,OAAO,EAAE,UAAU,EAAE,MAAM,iBAAiB,CAAC;AAC7C,OAAO,EAAE,KAAK,EAAE,MAAM,YAAY,CAAC;AAQnC,MAAM,WAAW,gBAAgB;IAC7B,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,OAAO,CAAC,EAAE,OAAO,CAAC;IAClB,SAAS,CAAC,EAAE,OAAO,CAAC;IACpB,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB,UAAU,CAAC,EAAE,OAAO,CAAC;IACrB,SAAS,CAAC,EAAE,OAAO,CAAC;IACpB,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,UAAU,CAAC,EAAE,OAAO,CAAC;IACrB,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,cAAc,CAAC,EAAE,MAAM,CAAC;IACxB,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,kBAAkB,CAAC,EAAE,OAAO,CAAC;IAC7B,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,KAAK,CAAC,EAAE,MAAM,CAAC;CAClB;AAED,KAAK,cAAc,GAAG,SAAS,GAAG;IAC9B,MAAM,EAAE,OAAO,CAAC;IAChB,UAAU,EAAE,MAAM,CAAC;IACnB,QAAQ,EAAE,MAAM,CAAC;IACjB,QAAQ,EAAE,MAAM,CAAC;CACpB,CAAC;AAEF,qBAAa,kBAAmB,SAAQ,aAAa,CAAC,cAAc,CAAC;IACjE,OAAO,CAAC,GAAG,CAA0B;IACrC,OAAO,CAAC,OAAO,CAAgB;IAC/B,OAAO,CAAC,MAAM,CAAsB;IACpC,OAAO,CAAC,KAAK,CAAqB;IAClC,OAAO,CAAC,OAAO,CAAqC;IACpD,OAAO,CAAC,aAAa,CAOnB;IACF,OAAO,CAAC,UAAU,CAA2B;IAC7C,OAAO,CAAC,WAAW,CAAuB;IAC1C,OAAO,CAAC,cAAc,CAAsC;IAC5D,OAAO,CAAC,aAAa,CAAgE;IACrF,OAAO,CAAC,WAAW,CAAiB;IACpC,OAAO,CAAC,KAAK,CAAc;IAC3B,OAAO,CAAC,aAAa,CAAkB;IACvC,OAAO,CAAC,eAAe,CAAiB;IACxC,OAAO,CAAC,YAAY,CAAc;IAClC,OAAO,CAAC,mBAAmB,CAAiB;IAC5C,OAAO,CAAC,YAAY,CAAiE;IACrF,OAAO,CAAC,aAAa,CAAsB;IAC3C,OAAO,CAAC,qBAAqB,CAAkB;gBAEnC,EAAE,EAAE,MAAM,EAAE,OAAO,GAAE,gBAAqB;IAmCtD,SAAS,CAAC,gBAAgB,IAAI,SAAS,MAAM,EAAE;IAC/C,SAAS,CAAC,iBAAiB,IAAI,SAAS,MAAM,EAAE;IAMhD,WAAW,CAAC,GAAG,EAAE,MAAM,GAAG,IAAI;IAwB9B,UAAU,CAAC,MAAM,EAAE,UAAU,GAAG,IAAI;IAWpC,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,EAAE,GAAG,MAAM,CAAC,MAAM,EAAE,GAAG,EAAE,CAAC,GAAG,IAAI;IAiBnE,UAAU,CAAC,KAAK,GAAE,MAAsB,EAAE,MAAM,GAAE,MAAoC,EAAE,IAAI,GAAE,MAAiB,GAAG,IAAI;IAStH,UAAU,CAAC,CAAC,EAAE,OAAO,GAAG,IAAI;IAC5B,UAAU,CAAC,CAAC,EAAE,MAAM,GAAG,IAAI;IAM3B,KAAK,CAAC,EAAE,EAAE,CAAC,EAAE,EAAE,SAAS,KAAK,SAAS,GAAG,IAAI;IAQ7C,MAAM,CAAC,SAAS,EAAE,CAAC,GAAG,EAAE,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,EAAE,KAAK,EAAE,MAAM,KAAK,OAAO,GAAG,IAAI;IAI7E,MAAM,CAAC,GAAG,IAAI,EAAE,MAAM,EAAE,GAAG,IAAI;IAI/B,IAAI,CAAC,GAAG,EAAE,MAAM,EAAE,UAAU,CAAC,EAAE,OAAO,GAAG,IAAI;IAI7C,IAAI,CAAC,CAAC,GAAE,MAAU,GAAG,IAAI;IAIzB,IAAI,CAAC,CAAC,GAAE,MAAU,GAAG,IAAI;IAIzB,UAAU,CAAC,IAAI,EAAE,MAAM,EAAE,EAAE,EAAE,CAAC,GAAG,EAAE,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,EAAE,KAAK,EAAE,MAAM,KAAK,GAAG,GAAG,IAAI;IAIpF,KAAK,CAAC,GAAG,EAAE,MAAM,EAAE,EAAE,EAAE,IAAI,GAAG,IAAI,GAAG,GAAG,GAAG,GAAG,GAAG,IAAI,GAAG,IAAI,GAAG,UAAU,GAAG,YAAY,GAAG,UAAU,EAAE,KAAK,EAAE,GAAG,GAAG,IAAI;IAQxH,IAAI,EAAE,IAAI,SAAS,GAAG,IAAI,CAAqB;IAC/C,IAAI,MAAM,IAAI,aAAa,CAAyB;IACpD,IAAI,KAAK,IAAI,KAAK,GAAG,IAAI,CAAwB;IACjD,QAAQ,IAAI,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,GAAG,IAAI;IACtC,KAAK,CAAC,SAAS,CAAC,EAAE,MAAM,GAAG,MAAM;IACjC,MAAM,IAAI,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,EAAE;IAC/B,IAAI,KAAK,IAAI,CAAC,MAAM,EAAE,MAAM,CAAC,CAAsC;IACnE,IAAI,OAAO,IAAI,MAAM,EAAE,CAAoC;IAErD,IAAI,CAAC,GAAG,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,GAAG,IAAI,CAAC;IAUhD,OAAO,CAAC,CAAC,EAAE,OAAO,GAAG,IAAI;IACzB,SAAS,CAAC,CAAC,EAAE,OAAO,GAAG,IAAI;IAC3B,QAAQ,CAAC,CAAC,EAAE,OAAO,GAAG,IAAI;IAC1B,UAAU,CAAC,CAAC,EAAE,OAAO,GAAG,IAAI;IAC5B,SAAS,CAAC,CAAC,EAAE,OAAO,GAAG,IAAI;IAC3B,WAAW,CAAC,CAAC,EAAE,MAAM,GAAG,IAAI;IAC5B,YAAY,CAAC,CAAC,EAAE,MAAM,GAAG,IAAI;IAC7B,cAAc,CAAC,CAAC,EAAE,MAAM,GAAG,IAAI;IAC/B,WAAW,CAAC,EAAE,EAAE,MAAM,GAAG,IAAI;YAMf,WAAW;IAyDzB,OAAO,CAAC,iBAAiB;
|
|
1
|
+
{"version":3,"file":"dataframe.d.ts","sourceRoot":"","sources":["dataframe.ts"],"names":[],"mappings":"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"}
|
|
@@ -3,7 +3,6 @@ import { DataFrame } from '../storage/DataFrame.js';
|
|
|
3
3
|
import { TabularDriver } from '../storage/TabularDriver.js';
|
|
4
4
|
import { FileUpload } from './fileupload.js';
|
|
5
5
|
import { Table } from './table.js';
|
|
6
|
-
import { Tabs } from './tabs.js';
|
|
7
6
|
import { Modal } from './modal.js';
|
|
8
7
|
import { renderIcon } from './icons.js';
|
|
9
8
|
const TRIGGER_EVENTS = [];
|
|
@@ -253,25 +252,62 @@ export class DataFrameComponent extends BaseComponent {
|
|
|
253
252
|
const existingTable = wrapper.querySelector('.jux-table-wrapper');
|
|
254
253
|
if (existingTable)
|
|
255
254
|
existingTable.remove();
|
|
255
|
+
const existingTabs = wrapper.querySelector('.jux-dataframe-tabs');
|
|
256
|
+
if (existingTabs)
|
|
257
|
+
existingTabs.remove();
|
|
256
258
|
Object.entries(sheets).forEach(([name, df]) => {
|
|
257
259
|
this._sheets.set(name, df);
|
|
258
260
|
});
|
|
259
261
|
const sheetNames = Object.keys(sheets);
|
|
260
|
-
|
|
261
|
-
tabs: sheetNames.map(name => ({
|
|
262
|
-
id: name,
|
|
263
|
-
label: name,
|
|
264
|
-
content: ''
|
|
265
|
-
})),
|
|
266
|
-
activeTab: sheetNames[0]
|
|
267
|
-
});
|
|
268
|
-
this._tabs = tabs;
|
|
262
|
+
// Build custom tab bar with settings cogs
|
|
269
263
|
const tabsContainer = document.createElement('div');
|
|
270
264
|
tabsContainer.className = 'jux-dataframe-tabs';
|
|
265
|
+
const tabList = document.createElement('div');
|
|
266
|
+
tabList.className = 'jux-tabs-list';
|
|
267
|
+
sheetNames.forEach((sheetName, idx) => {
|
|
268
|
+
const tabBtn = document.createElement('button');
|
|
269
|
+
tabBtn.className = 'jux-tabs-button' + (idx === 0 ? ' jux-tabs-button-active' : '');
|
|
270
|
+
tabBtn.setAttribute('data-sheet', sheetName);
|
|
271
|
+
const labelSpan = document.createElement('span');
|
|
272
|
+
labelSpan.textContent = sheetName;
|
|
273
|
+
tabBtn.appendChild(labelSpan);
|
|
274
|
+
// Add settings cog icon
|
|
275
|
+
const cogBtn = document.createElement('button');
|
|
276
|
+
cogBtn.className = 'jux-dataframe-tab-settings';
|
|
277
|
+
cogBtn.title = 'Import settings for ' + sheetName;
|
|
278
|
+
cogBtn.innerHTML = `<span class="iconify" data-icon="lucide:settings" style="width:14px;height:14px;"></span>`;
|
|
279
|
+
cogBtn.addEventListener('click', (e) => {
|
|
280
|
+
e.stopPropagation();
|
|
281
|
+
this._showReshapeModal();
|
|
282
|
+
});
|
|
283
|
+
tabBtn.appendChild(cogBtn);
|
|
284
|
+
tabBtn.addEventListener('click', () => {
|
|
285
|
+
// Switch active tab
|
|
286
|
+
tabList.querySelectorAll('.jux-tabs-button').forEach(btn => {
|
|
287
|
+
btn.classList.remove('jux-tabs-button-active');
|
|
288
|
+
});
|
|
289
|
+
tabBtn.classList.add('jux-tabs-button-active');
|
|
290
|
+
// Show/hide panels
|
|
291
|
+
wrapper.querySelectorAll('.jux-tabs-panel').forEach(panel => {
|
|
292
|
+
panel.style.display = 'none';
|
|
293
|
+
});
|
|
294
|
+
const panel = document.getElementById(`${this._id}-panel-${sheetName}`);
|
|
295
|
+
if (panel)
|
|
296
|
+
panel.style.display = 'block';
|
|
297
|
+
// Update current df reference
|
|
298
|
+
this._df = this._sheets.get(sheetName) || null;
|
|
299
|
+
});
|
|
300
|
+
tabList.appendChild(tabBtn);
|
|
301
|
+
});
|
|
302
|
+
tabsContainer.appendChild(tabList);
|
|
271
303
|
wrapper.appendChild(tabsContainer);
|
|
272
|
-
|
|
273
|
-
sheetNames.forEach(sheetName => {
|
|
304
|
+
// Create panels for each sheet
|
|
305
|
+
sheetNames.forEach((sheetName, idx) => {
|
|
274
306
|
const df = sheets[sheetName];
|
|
307
|
+
const panel = document.createElement('div');
|
|
308
|
+
panel.className = 'jux-tabs-panel';
|
|
309
|
+
panel.id = `${this._id}-panel-${sheetName}`;
|
|
310
|
+
panel.style.display = idx === 0 ? 'block' : 'none';
|
|
275
311
|
const table = new Table(`${this._id}-table-${sheetName}`, {
|
|
276
312
|
striped: this._tableOptions.striped,
|
|
277
313
|
hoverable: this._tableOptions.hoverable,
|
|
@@ -282,10 +318,8 @@ export class DataFrameComponent extends BaseComponent {
|
|
|
282
318
|
});
|
|
283
319
|
const columnDefs = df.columns.map(col => ({ key: col, label: col }));
|
|
284
320
|
table.columns(columnDefs).rows(df.toRows());
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
return;
|
|
288
|
-
table.render(tabPanel);
|
|
321
|
+
wrapper.appendChild(panel);
|
|
322
|
+
table.render(panel);
|
|
289
323
|
if (this._tableOptions.filterable) {
|
|
290
324
|
const filterContainer = document.createElement('div');
|
|
291
325
|
filterContainer.className = 'jux-dataframe-filter';
|
|
@@ -310,12 +344,18 @@ export class DataFrameComponent extends BaseComponent {
|
|
|
310
344
|
const filtered = df.filter((row) => Object.values(row).some(v => v !== null && v !== undefined && String(v).toLowerCase().includes(text)));
|
|
311
345
|
table.rows(filtered.toRows());
|
|
312
346
|
});
|
|
313
|
-
const tableWrapper =
|
|
347
|
+
const tableWrapper = panel.querySelector('.jux-table-wrapper');
|
|
314
348
|
if (tableWrapper) {
|
|
315
|
-
|
|
349
|
+
panel.insertBefore(filterContainer, tableWrapper);
|
|
316
350
|
}
|
|
317
351
|
}
|
|
318
352
|
});
|
|
353
|
+
// Ensure Iconify renders the cog icons
|
|
354
|
+
requestAnimationFrame(() => {
|
|
355
|
+
if (window.Iconify) {
|
|
356
|
+
window.Iconify.scan();
|
|
357
|
+
}
|
|
358
|
+
});
|
|
319
359
|
const totalRows = Object.values(sheets).reduce((sum, df) => sum + df.height, 0);
|
|
320
360
|
this._updateStatus(`${sourceName} — ${sheetNames.length} sheets, ${totalRows} total rows`, 'success');
|
|
321
361
|
this._df = sheets[sheetNames[0]];
|
|
@@ -486,14 +526,14 @@ export class DataFrameComponent extends BaseComponent {
|
|
|
486
526
|
max="50"
|
|
487
527
|
style="width: 100%;"
|
|
488
528
|
/>
|
|
489
|
-
<div id="${this._id}-reshape-hint" class="jux-reshape-hint">
|
|
529
|
+
<div id="${this._id}-reshape-hint" class="jux-reshape-hint" style="margin-top: 0.5rem; padding: 0.75rem; background: hsl(var(--muted) / 0.5); border-radius: var(--radius); font-size: 0.875rem;">
|
|
490
530
|
</div>
|
|
491
531
|
</div>
|
|
492
532
|
<div class="jux-reshape-preview-container">
|
|
493
533
|
<div style="font-weight: 600; margin-bottom: 0.5rem; color: hsl(var(--foreground));">
|
|
494
534
|
Preview
|
|
495
535
|
</div>
|
|
496
|
-
<div id="${this._id}-preview"
|
|
536
|
+
<div id="${this._id}-preview" style="font-family: monospace; font-size: 0.75rem; background: hsl(var(--muted) / 0.3); border: 1px solid hsl(var(--border)); border-radius: var(--radius); padding: 1rem; overflow-x: auto; white-space: pre; max-height: 400px; overflow-y: auto;"></div>
|
|
497
537
|
</div>
|
|
498
538
|
`;
|
|
499
539
|
this._reshapeModal
|
|
@@ -543,62 +583,84 @@ export class DataFrameComponent extends BaseComponent {
|
|
|
543
583
|
const updateHint = (headerRow) => {
|
|
544
584
|
if (!hintDiv)
|
|
545
585
|
return;
|
|
546
|
-
|
|
547
|
-
|
|
548
|
-
`
|
|
549
|
-
|
|
586
|
+
if (headerRow > 0) {
|
|
587
|
+
hintDiv.innerHTML = `Row <strong>${headerRow}</strong> will be used as column headers. ` +
|
|
588
|
+
`Rows <strong>0–${headerRow - 1}</strong> will be skipped (not imported).`;
|
|
589
|
+
}
|
|
590
|
+
else {
|
|
591
|
+
hintDiv.innerHTML = `Row <strong>0</strong> (first row) will be used as column headers. No rows will be skipped.`;
|
|
592
|
+
}
|
|
550
593
|
};
|
|
551
594
|
const updatePreview = async () => {
|
|
552
595
|
const headerRow = parseInt(headerRowInput?.value) || 0;
|
|
553
596
|
updateHint(headerRow);
|
|
554
597
|
try {
|
|
555
|
-
//
|
|
598
|
+
// Get raw data (headerRow=0) to show ALL rows including skipped ones
|
|
556
599
|
const rawSheets = await this._driver.streamFileMultiSheet(this._rawFileData.file, {
|
|
557
600
|
headerRow: 0,
|
|
558
|
-
maxSheetSize: headerRow +
|
|
601
|
+
maxSheetSize: headerRow + 12
|
|
559
602
|
});
|
|
560
603
|
const rawSheet = Object.values(rawSheets)[0];
|
|
561
|
-
|
|
562
|
-
const parsedSheets = await this._driver.streamFileMultiSheet(this._rawFileData.file, {
|
|
563
|
-
headerRow,
|
|
564
|
-
maxSheetSize: headerRow + 15
|
|
565
|
-
});
|
|
566
|
-
const parsedSheet = Object.values(parsedSheets)[0];
|
|
567
|
-
if (!rawSheet && !parsedSheet) {
|
|
604
|
+
if (!rawSheet) {
|
|
568
605
|
if (previewDiv)
|
|
569
606
|
previewDiv.textContent = 'No data found';
|
|
570
607
|
return;
|
|
571
608
|
}
|
|
572
|
-
const
|
|
573
|
-
const
|
|
609
|
+
const rawCols = rawSheet.columns;
|
|
610
|
+
const rawRows = rawSheet.toRows();
|
|
611
|
+
const colWidth = 20;
|
|
574
612
|
const lines = [];
|
|
575
|
-
//
|
|
576
|
-
if (
|
|
577
|
-
|
|
578
|
-
|
|
579
|
-
|
|
580
|
-
|
|
581
|
-
|
|
582
|
-
const
|
|
583
|
-
|
|
613
|
+
// === SKIPPED ROWS SECTION ===
|
|
614
|
+
if (headerRow > 0) {
|
|
615
|
+
lines.push('┌─────────────────────────────────────────────────────────────────────────────────┐');
|
|
616
|
+
lines.push(`│ SKIPPED: Rows 0–${headerRow - 1} will NOT be imported │`);
|
|
617
|
+
lines.push('└─────────────────────────────────────────────────────────────────────────────────┘');
|
|
618
|
+
lines.push('');
|
|
619
|
+
// Row 0 is the raw file header (becomes column names when headerRow=0)
|
|
620
|
+
const row0Line = rawCols.slice(0, 5).map(c => String(c ?? '').substring(0, colWidth - 1).padEnd(colWidth)).join('│');
|
|
621
|
+
lines.push(` [0] ${row0Line}${rawCols.length > 5 ? ' ...' : ''}`);
|
|
622
|
+
// Rows 1 to headerRow-1 are skipped data rows
|
|
623
|
+
for (let i = 0; i < Math.min(headerRow - 1, rawRows.length); i++) {
|
|
584
624
|
const row = rawRows[i];
|
|
585
|
-
const
|
|
586
|
-
|
|
587
|
-
lines.push(`${rowIdx}${cols}`);
|
|
625
|
+
const vals = Object.values(row).slice(0, 5).map(v => String(v ?? '').substring(0, colWidth - 1).padEnd(colWidth)).join('│');
|
|
626
|
+
lines.push(` [${i + 1}] ${vals}${Object.values(row).length > 5 ? ' ...' : ''}`);
|
|
588
627
|
}
|
|
589
|
-
|
|
590
|
-
lines.push(`${'─'.repeat(6)}${'── skipped '.padEnd(colWidth * Math.min(rawCols.length, 5), '─')}`);
|
|
628
|
+
lines.push('');
|
|
591
629
|
}
|
|
592
|
-
//
|
|
593
|
-
|
|
594
|
-
|
|
595
|
-
|
|
596
|
-
|
|
597
|
-
|
|
630
|
+
// === HEADER ROW (will become column names) ===
|
|
631
|
+
lines.push('╔═════════════════════════════════════════════════════════════════════════════════╗');
|
|
632
|
+
lines.push(`║ HEADER ROW ${headerRow} — These values become your column names ║`);
|
|
633
|
+
lines.push('╚═════════════════════════════════════════════════════════════════════════════════╝');
|
|
634
|
+
lines.push('');
|
|
635
|
+
// The header row content - if headerRow=0, it's rawCols, else it's rawRows[headerRow-1]
|
|
636
|
+
let headerValues;
|
|
637
|
+
if (headerRow === 0) {
|
|
638
|
+
headerValues = rawCols;
|
|
639
|
+
}
|
|
640
|
+
else if (headerRow - 1 < rawRows.length) {
|
|
641
|
+
headerValues = Object.values(rawRows[headerRow - 1]).map(v => String(v ?? ''));
|
|
642
|
+
}
|
|
643
|
+
else {
|
|
644
|
+
headerValues = rawCols; // fallback
|
|
645
|
+
}
|
|
646
|
+
const headerLine = headerValues.slice(0, 5).map(c => String(c ?? '').substring(0, colWidth - 1).padEnd(colWidth)).join('│');
|
|
647
|
+
lines.push(`▶ [${headerRow}] ${headerLine}${headerValues.length > 5 ? ' ...' : ''}`);
|
|
648
|
+
lines.push('');
|
|
649
|
+
// === DATA ROWS ===
|
|
650
|
+
lines.push('────────────────────────────────────────────────────────────────────────────────────');
|
|
651
|
+
lines.push(' DATA ROWS (will be imported):');
|
|
652
|
+
lines.push('');
|
|
653
|
+
// Data starts at rawRows[headerRow] (since rawRows is 0-indexed after the header)
|
|
654
|
+
const dataStartIdx = headerRow;
|
|
655
|
+
const dataRows = rawRows.slice(dataStartIdx, dataStartIdx + 6);
|
|
656
|
+
if (dataRows.length === 0) {
|
|
657
|
+
lines.push(' (No data rows found after header)');
|
|
658
|
+
}
|
|
659
|
+
else {
|
|
598
660
|
dataRows.forEach((row, i) => {
|
|
599
|
-
const rowIdx =
|
|
600
|
-
const
|
|
601
|
-
lines.push(
|
|
661
|
+
const rowIdx = headerRow + 1 + i;
|
|
662
|
+
const vals = Object.values(row).slice(0, 5).map(v => String(v ?? '').substring(0, colWidth - 1).padEnd(colWidth)).join('│');
|
|
663
|
+
lines.push(` [${rowIdx}] ${vals}${Object.values(row).length > 5 ? ' ...' : ''}`);
|
|
602
664
|
});
|
|
603
665
|
}
|
|
604
666
|
if (previewDiv) {
|
|
@@ -736,17 +798,26 @@ export class DataFrameComponent extends BaseComponent {
|
|
|
736
798
|
hasHeader: true,
|
|
737
799
|
maxRows: totalOffset + 1
|
|
738
800
|
});
|
|
801
|
+
lines.push('');
|
|
802
|
+
lines.push(` ┌${'─'.repeat(100)}┐`);
|
|
803
|
+
lines.push(` │ ROWS 0-${totalOffset - 1} WILL BE SKIPPED (not imported)`.padEnd(101) + '│');
|
|
804
|
+
lines.push(` └${'─'.repeat(100)}┘`);
|
|
805
|
+
lines.push('');
|
|
739
806
|
const rawCols = rawDf.columns;
|
|
740
|
-
lines.push(`${'
|
|
807
|
+
lines.push(`${'[0]'.padEnd(idxWidth)}${rawCols.map(c => String(c).substring(0, colWidth - 2).padEnd(colWidth)).join('│ ')} ← skipped`);
|
|
741
808
|
const rawRows = rawDf.toRows();
|
|
742
809
|
const skippedCount = Math.min(totalOffset - 1, rawRows.length);
|
|
743
810
|
for (let i = 0; i < skippedCount; i++) {
|
|
744
811
|
const row = rawRows[i];
|
|
745
|
-
const rowIdx =
|
|
746
|
-
const cols = Object.values(row).map(v => String(v ?? '').substring(0, colWidth - 2).padEnd(colWidth)).join('
|
|
747
|
-
lines.push(`${rowIdx}${cols}`);
|
|
812
|
+
const rowIdx = `[${i + 1}]`.padEnd(idxWidth);
|
|
813
|
+
const cols = Object.values(row).map(v => String(v ?? '').substring(0, colWidth - 2).padEnd(colWidth)).join('│ ');
|
|
814
|
+
lines.push(`${rowIdx}${cols} ← skipped`);
|
|
748
815
|
}
|
|
749
|
-
lines.push(
|
|
816
|
+
lines.push('');
|
|
817
|
+
lines.push(` ╔${'═'.repeat(100)}╗`);
|
|
818
|
+
lines.push(` ║ ▼ DATA STARTS HERE (Row ${totalOffset} = Column Headers)`.padEnd(101) + '║');
|
|
819
|
+
lines.push(` ╚${'═'.repeat(100)}╝`);
|
|
820
|
+
lines.push('');
|
|
750
821
|
}
|
|
751
822
|
// Parse with actual settings for header + data rows
|
|
752
823
|
const df = this._driver.parseCSV(this._rawFileData.text, {
|
|
@@ -756,13 +827,13 @@ export class DataFrameComponent extends BaseComponent {
|
|
|
756
827
|
hasHeader: true,
|
|
757
828
|
maxRows: 8
|
|
758
829
|
});
|
|
759
|
-
const headerLine = `${'
|
|
830
|
+
const headerLine = `${'HDR'.padEnd(idxWidth)}${df.columns.map(c => String(c).substring(0, colWidth - 2).padEnd(colWidth)).join('│ ')} ◀ HEADERS`;
|
|
760
831
|
lines.push(headerLine);
|
|
761
|
-
lines.push('
|
|
832
|
+
lines.push(`${'───'.padEnd(idxWidth)}${'─'.repeat(Math.min(colWidth * df.columns.length, 120))}`);
|
|
762
833
|
const dataRows = df.toRows();
|
|
763
834
|
dataRows.forEach((row, i) => {
|
|
764
|
-
const rowIdx =
|
|
765
|
-
const cols = Object.values(row).map(v => String(v ?? '').substring(0, colWidth - 2).padEnd(colWidth)).join('
|
|
835
|
+
const rowIdx = `[${totalOffset + 1 + i}]`.padEnd(idxWidth);
|
|
836
|
+
const cols = Object.values(row).map(v => String(v ?? '').substring(0, colWidth - 2).padEnd(colWidth)).join('│ ');
|
|
766
837
|
lines.push(`${rowIdx}${cols}`);
|
|
767
838
|
});
|
|
768
839
|
if (previewDiv) {
|
|
@@ -314,32 +314,75 @@ export class DataFrameComponent extends BaseComponent<DataFrameState> {
|
|
|
314
314
|
const existingTable = wrapper.querySelector('.jux-table-wrapper');
|
|
315
315
|
if (existingTable) existingTable.remove();
|
|
316
316
|
|
|
317
|
+
const existingTabs = wrapper.querySelector('.jux-dataframe-tabs');
|
|
318
|
+
if (existingTabs) existingTabs.remove();
|
|
319
|
+
|
|
317
320
|
Object.entries(sheets).forEach(([name, df]) => {
|
|
318
321
|
this._sheets.set(name, df);
|
|
319
322
|
});
|
|
320
323
|
|
|
321
324
|
const sheetNames = Object.keys(sheets);
|
|
322
325
|
|
|
323
|
-
|
|
324
|
-
tabs: sheetNames.map(name => ({
|
|
325
|
-
id: name,
|
|
326
|
-
label: name,
|
|
327
|
-
content: ''
|
|
328
|
-
})),
|
|
329
|
-
activeTab: sheetNames[0]
|
|
330
|
-
});
|
|
331
|
-
|
|
332
|
-
this._tabs = tabs;
|
|
333
|
-
|
|
326
|
+
// Build custom tab bar with settings cogs
|
|
334
327
|
const tabsContainer = document.createElement('div');
|
|
335
328
|
tabsContainer.className = 'jux-dataframe-tabs';
|
|
336
|
-
wrapper.appendChild(tabsContainer);
|
|
337
329
|
|
|
338
|
-
|
|
330
|
+
const tabList = document.createElement('div');
|
|
331
|
+
tabList.className = 'jux-tabs-list';
|
|
332
|
+
|
|
333
|
+
sheetNames.forEach((sheetName, idx) => {
|
|
334
|
+
const tabBtn = document.createElement('button');
|
|
335
|
+
tabBtn.className = 'jux-tabs-button' + (idx === 0 ? ' jux-tabs-button-active' : '');
|
|
336
|
+
tabBtn.setAttribute('data-sheet', sheetName);
|
|
337
|
+
|
|
338
|
+
const labelSpan = document.createElement('span');
|
|
339
|
+
labelSpan.textContent = sheetName;
|
|
340
|
+
tabBtn.appendChild(labelSpan);
|
|
341
|
+
|
|
342
|
+
// Add settings cog icon
|
|
343
|
+
const cogBtn = document.createElement('button');
|
|
344
|
+
cogBtn.className = 'jux-dataframe-tab-settings';
|
|
345
|
+
cogBtn.title = 'Import settings for ' + sheetName;
|
|
346
|
+
cogBtn.innerHTML = `<span class="iconify" data-icon="lucide:settings" style="width:14px;height:14px;"></span>`;
|
|
347
|
+
cogBtn.addEventListener('click', (e) => {
|
|
348
|
+
e.stopPropagation();
|
|
349
|
+
this._showReshapeModal();
|
|
350
|
+
});
|
|
351
|
+
tabBtn.appendChild(cogBtn);
|
|
352
|
+
|
|
353
|
+
tabBtn.addEventListener('click', () => {
|
|
354
|
+
// Switch active tab
|
|
355
|
+
tabList.querySelectorAll('.jux-tabs-button').forEach(btn => {
|
|
356
|
+
btn.classList.remove('jux-tabs-button-active');
|
|
357
|
+
});
|
|
358
|
+
tabBtn.classList.add('jux-tabs-button-active');
|
|
359
|
+
|
|
360
|
+
// Show/hide panels
|
|
361
|
+
wrapper.querySelectorAll('.jux-tabs-panel').forEach(panel => {
|
|
362
|
+
(panel as HTMLElement).style.display = 'none';
|
|
363
|
+
});
|
|
364
|
+
const panel = document.getElementById(`${this._id}-panel-${sheetName}`);
|
|
365
|
+
if (panel) panel.style.display = 'block';
|
|
339
366
|
|
|
340
|
-
|
|
367
|
+
// Update current df reference
|
|
368
|
+
this._df = this._sheets.get(sheetName) || null;
|
|
369
|
+
});
|
|
370
|
+
|
|
371
|
+
tabList.appendChild(tabBtn);
|
|
372
|
+
});
|
|
373
|
+
|
|
374
|
+
tabsContainer.appendChild(tabList);
|
|
375
|
+
wrapper.appendChild(tabsContainer);
|
|
376
|
+
|
|
377
|
+
// Create panels for each sheet
|
|
378
|
+
sheetNames.forEach((sheetName, idx) => {
|
|
341
379
|
const df = sheets[sheetName];
|
|
342
380
|
|
|
381
|
+
const panel = document.createElement('div');
|
|
382
|
+
panel.className = 'jux-tabs-panel';
|
|
383
|
+
panel.id = `${this._id}-panel-${sheetName}`;
|
|
384
|
+
panel.style.display = idx === 0 ? 'block' : 'none';
|
|
385
|
+
|
|
343
386
|
const table = new Table(`${this._id}-table-${sheetName}`, {
|
|
344
387
|
striped: this._tableOptions.striped,
|
|
345
388
|
hoverable: this._tableOptions.hoverable,
|
|
@@ -352,10 +395,8 @@ export class DataFrameComponent extends BaseComponent<DataFrameState> {
|
|
|
352
395
|
const columnDefs = df.columns.map(col => ({ key: col, label: col }));
|
|
353
396
|
table.columns(columnDefs).rows(df.toRows());
|
|
354
397
|
|
|
355
|
-
|
|
356
|
-
|
|
357
|
-
|
|
358
|
-
table.render(tabPanel);
|
|
398
|
+
wrapper.appendChild(panel);
|
|
399
|
+
table.render(panel);
|
|
359
400
|
|
|
360
401
|
if (this._tableOptions.filterable) {
|
|
361
402
|
const filterContainer = document.createElement('div');
|
|
@@ -388,13 +429,20 @@ export class DataFrameComponent extends BaseComponent<DataFrameState> {
|
|
|
388
429
|
table.rows(filtered.toRows());
|
|
389
430
|
});
|
|
390
431
|
|
|
391
|
-
const tableWrapper =
|
|
432
|
+
const tableWrapper = panel.querySelector('.jux-table-wrapper');
|
|
392
433
|
if (tableWrapper) {
|
|
393
|
-
|
|
434
|
+
panel.insertBefore(filterContainer, tableWrapper);
|
|
394
435
|
}
|
|
395
436
|
}
|
|
396
437
|
});
|
|
397
438
|
|
|
439
|
+
// Ensure Iconify renders the cog icons
|
|
440
|
+
requestAnimationFrame(() => {
|
|
441
|
+
if ((window as any).Iconify) {
|
|
442
|
+
(window as any).Iconify.scan();
|
|
443
|
+
}
|
|
444
|
+
});
|
|
445
|
+
|
|
398
446
|
const totalRows = Object.values(sheets).reduce((sum, df) => sum + df.height, 0);
|
|
399
447
|
this._updateStatus(
|
|
400
448
|
`${sourceName} — ${sheetNames.length} sheets, ${totalRows} total rows`,
|
|
@@ -604,14 +652,14 @@ export class DataFrameComponent extends BaseComponent<DataFrameState> {
|
|
|
604
652
|
max="50"
|
|
605
653
|
style="width: 100%;"
|
|
606
654
|
/>
|
|
607
|
-
<div id="${this._id}-reshape-hint" class="jux-reshape-hint">
|
|
655
|
+
<div id="${this._id}-reshape-hint" class="jux-reshape-hint" style="margin-top: 0.5rem; padding: 0.75rem; background: hsl(var(--muted) / 0.5); border-radius: var(--radius); font-size: 0.875rem;">
|
|
608
656
|
</div>
|
|
609
657
|
</div>
|
|
610
658
|
<div class="jux-reshape-preview-container">
|
|
611
659
|
<div style="font-weight: 600; margin-bottom: 0.5rem; color: hsl(var(--foreground));">
|
|
612
660
|
Preview
|
|
613
661
|
</div>
|
|
614
|
-
<div id="${this._id}-preview"
|
|
662
|
+
<div id="${this._id}-preview" style="font-family: monospace; font-size: 0.75rem; background: hsl(var(--muted) / 0.3); border: 1px solid hsl(var(--border)); border-radius: var(--radius); padding: 1rem; overflow-x: auto; white-space: pre; max-height: 400px; overflow-y: auto;"></div>
|
|
615
663
|
</div>
|
|
616
664
|
`;
|
|
617
665
|
|
|
@@ -668,10 +716,12 @@ export class DataFrameComponent extends BaseComponent<DataFrameState> {
|
|
|
668
716
|
|
|
669
717
|
const updateHint = (headerRow: number) => {
|
|
670
718
|
if (!hintDiv) return;
|
|
671
|
-
|
|
672
|
-
|
|
673
|
-
|
|
674
|
-
|
|
719
|
+
if (headerRow > 0) {
|
|
720
|
+
hintDiv.innerHTML = `Row <strong>${headerRow}</strong> will be used as column headers. ` +
|
|
721
|
+
`Rows <strong>0–${headerRow - 1}</strong> will be skipped (not imported).`;
|
|
722
|
+
} else {
|
|
723
|
+
hintDiv.innerHTML = `Row <strong>0</strong> (first row) will be used as column headers. No rows will be skipped.`;
|
|
724
|
+
}
|
|
675
725
|
};
|
|
676
726
|
|
|
677
727
|
const updatePreview = async () => {
|
|
@@ -679,60 +729,80 @@ export class DataFrameComponent extends BaseComponent<DataFrameState> {
|
|
|
679
729
|
updateHint(headerRow);
|
|
680
730
|
|
|
681
731
|
try {
|
|
682
|
-
//
|
|
732
|
+
// Get raw data (headerRow=0) to show ALL rows including skipped ones
|
|
683
733
|
const rawSheets = await this._driver.streamFileMultiSheet(this._rawFileData!.file, {
|
|
684
734
|
headerRow: 0,
|
|
685
|
-
maxSheetSize: headerRow +
|
|
735
|
+
maxSheetSize: headerRow + 12
|
|
686
736
|
});
|
|
687
737
|
const rawSheet = Object.values(rawSheets)[0];
|
|
688
738
|
|
|
689
|
-
|
|
690
|
-
const parsedSheets = await this._driver.streamFileMultiSheet(this._rawFileData!.file, {
|
|
691
|
-
headerRow,
|
|
692
|
-
maxSheetSize: headerRow + 15
|
|
693
|
-
});
|
|
694
|
-
const parsedSheet = Object.values(parsedSheets)[0];
|
|
695
|
-
|
|
696
|
-
if (!rawSheet && !parsedSheet) {
|
|
739
|
+
if (!rawSheet) {
|
|
697
740
|
if (previewDiv) previewDiv.textContent = 'No data found';
|
|
698
741
|
return;
|
|
699
742
|
}
|
|
700
743
|
|
|
701
|
-
const
|
|
702
|
-
const
|
|
744
|
+
const rawCols = rawSheet.columns;
|
|
745
|
+
const rawRows = rawSheet.toRows();
|
|
746
|
+
const colWidth = 20;
|
|
703
747
|
const lines: string[] = [];
|
|
704
748
|
|
|
705
|
-
//
|
|
706
|
-
if (
|
|
707
|
-
|
|
708
|
-
|
|
709
|
-
|
|
710
|
-
|
|
711
|
-
lines.push(`${'Idx'.padEnd(idxWidth)}${rawCols.map(c => String(c).substring(0, colWidth - 2).padEnd(colWidth)).join('| ')}`);
|
|
749
|
+
// === SKIPPED ROWS SECTION ===
|
|
750
|
+
if (headerRow > 0) {
|
|
751
|
+
lines.push('┌─────────────────────────────────────────────────────────────────────────────────┐');
|
|
752
|
+
lines.push(`│ SKIPPED: Rows 0–${headerRow - 1} will NOT be imported │`);
|
|
753
|
+
lines.push('└─────────────────────────────────────────────────────────────────────────────────┘');
|
|
754
|
+
lines.push('');
|
|
712
755
|
|
|
713
|
-
|
|
714
|
-
|
|
756
|
+
// Row 0 is the raw file header (becomes column names when headerRow=0)
|
|
757
|
+
const row0Line = rawCols.slice(0, 5).map(c => String(c ?? '').substring(0, colWidth - 1).padEnd(colWidth)).join('│');
|
|
758
|
+
lines.push(` [0] ${row0Line}${rawCols.length > 5 ? ' ...' : ''}`);
|
|
759
|
+
|
|
760
|
+
// Rows 1 to headerRow-1 are skipped data rows
|
|
761
|
+
for (let i = 0; i < Math.min(headerRow - 1, rawRows.length); i++) {
|
|
715
762
|
const row = rawRows[i];
|
|
716
|
-
const
|
|
717
|
-
|
|
718
|
-
lines.push(`${rowIdx}${cols}`);
|
|
763
|
+
const vals = Object.values(row).slice(0, 5).map(v => String(v ?? '').substring(0, colWidth - 1).padEnd(colWidth)).join('│');
|
|
764
|
+
lines.push(` [${i + 1}] ${vals}${Object.values(row).length > 5 ? ' ...' : ''}`);
|
|
719
765
|
}
|
|
720
766
|
|
|
721
|
-
|
|
722
|
-
lines.push(`${'─'.repeat(6)}${'── skipped '.padEnd(colWidth * Math.min(rawCols.length, 5), '─')}`);
|
|
767
|
+
lines.push('');
|
|
723
768
|
}
|
|
724
769
|
|
|
725
|
-
//
|
|
726
|
-
|
|
727
|
-
|
|
728
|
-
|
|
729
|
-
|
|
770
|
+
// === HEADER ROW (will become column names) ===
|
|
771
|
+
lines.push('╔═════════════════════════════════════════════════════════════════════════════════╗');
|
|
772
|
+
lines.push(`║ HEADER ROW ${headerRow} — These values become your column names ║`);
|
|
773
|
+
lines.push('╚═════════════════════════════════════════════════════════════════════════════════╝');
|
|
774
|
+
lines.push('');
|
|
775
|
+
|
|
776
|
+
// The header row content - if headerRow=0, it's rawCols, else it's rawRows[headerRow-1]
|
|
777
|
+
let headerValues: string[];
|
|
778
|
+
if (headerRow === 0) {
|
|
779
|
+
headerValues = rawCols;
|
|
780
|
+
} else if (headerRow - 1 < rawRows.length) {
|
|
781
|
+
headerValues = Object.values(rawRows[headerRow - 1]).map(v => String(v ?? ''));
|
|
782
|
+
} else {
|
|
783
|
+
headerValues = rawCols; // fallback
|
|
784
|
+
}
|
|
785
|
+
|
|
786
|
+
const headerLine = headerValues.slice(0, 5).map(c => String(c ?? '').substring(0, colWidth - 1).padEnd(colWidth)).join('│');
|
|
787
|
+
lines.push(`▶ [${headerRow}] ${headerLine}${headerValues.length > 5 ? ' ...' : ''}`);
|
|
788
|
+
lines.push('');
|
|
789
|
+
|
|
790
|
+
// === DATA ROWS ===
|
|
791
|
+
lines.push('────────────────────────────────────────────────────────────────────────────────────');
|
|
792
|
+
lines.push(' DATA ROWS (will be imported):');
|
|
793
|
+
lines.push('');
|
|
730
794
|
|
|
731
|
-
|
|
795
|
+
// Data starts at rawRows[headerRow] (since rawRows is 0-indexed after the header)
|
|
796
|
+
const dataStartIdx = headerRow;
|
|
797
|
+
const dataRows = rawRows.slice(dataStartIdx, dataStartIdx + 6);
|
|
798
|
+
|
|
799
|
+
if (dataRows.length === 0) {
|
|
800
|
+
lines.push(' (No data rows found after header)');
|
|
801
|
+
} else {
|
|
732
802
|
dataRows.forEach((row, i) => {
|
|
733
|
-
const rowIdx =
|
|
734
|
-
const
|
|
735
|
-
lines.push(
|
|
803
|
+
const rowIdx = headerRow + 1 + i;
|
|
804
|
+
const vals = Object.values(row).slice(0, 5).map(v => String(v ?? '').substring(0, colWidth - 1).padEnd(colWidth)).join('│');
|
|
805
|
+
lines.push(` [${rowIdx}] ${vals}${Object.values(row).length > 5 ? ' ...' : ''}`);
|
|
736
806
|
});
|
|
737
807
|
}
|
|
738
808
|
|
|
@@ -885,19 +955,29 @@ export class DataFrameComponent extends BaseComponent<DataFrameState> {
|
|
|
885
955
|
maxRows: totalOffset + 1
|
|
886
956
|
});
|
|
887
957
|
|
|
958
|
+
lines.push('');
|
|
959
|
+
lines.push(` ┌${'─'.repeat(100)}┐`);
|
|
960
|
+
lines.push(` │ ROWS 0-${totalOffset - 1} WILL BE SKIPPED (not imported)`.padEnd(101) + '│');
|
|
961
|
+
lines.push(` └${'─'.repeat(100)}┘`);
|
|
962
|
+
lines.push('');
|
|
963
|
+
|
|
888
964
|
const rawCols = rawDf.columns;
|
|
889
|
-
lines.push(`${'
|
|
965
|
+
lines.push(`${'[0]'.padEnd(idxWidth)}${rawCols.map(c => String(c).substring(0, colWidth - 2).padEnd(colWidth)).join('│ ')} ← skipped`);
|
|
890
966
|
|
|
891
967
|
const rawRows = rawDf.toRows();
|
|
892
968
|
const skippedCount = Math.min(totalOffset - 1, rawRows.length);
|
|
893
969
|
for (let i = 0; i < skippedCount; i++) {
|
|
894
970
|
const row = rawRows[i];
|
|
895
|
-
const rowIdx =
|
|
896
|
-
const cols = Object.values(row).map(v => String(v ?? '').substring(0, colWidth - 2).padEnd(colWidth)).join('
|
|
897
|
-
lines.push(`${rowIdx}${cols}`);
|
|
971
|
+
const rowIdx = `[${i + 1}]`.padEnd(idxWidth);
|
|
972
|
+
const cols = Object.values(row).map(v => String(v ?? '').substring(0, colWidth - 2).padEnd(colWidth)).join('│ ');
|
|
973
|
+
lines.push(`${rowIdx}${cols} ← skipped`);
|
|
898
974
|
}
|
|
899
975
|
|
|
900
|
-
lines.push(
|
|
976
|
+
lines.push('');
|
|
977
|
+
lines.push(` ╔${'═'.repeat(100)}╗`);
|
|
978
|
+
lines.push(` ║ ▼ DATA STARTS HERE (Row ${totalOffset} = Column Headers)`.padEnd(101) + '║');
|
|
979
|
+
lines.push(` ╚${'═'.repeat(100)}╝`);
|
|
980
|
+
lines.push('');
|
|
901
981
|
}
|
|
902
982
|
|
|
903
983
|
// Parse with actual settings for header + data rows
|
|
@@ -909,14 +989,14 @@ export class DataFrameComponent extends BaseComponent<DataFrameState> {
|
|
|
909
989
|
maxRows: 8
|
|
910
990
|
});
|
|
911
991
|
|
|
912
|
-
const headerLine = `${'
|
|
992
|
+
const headerLine = `${'HDR'.padEnd(idxWidth)}${df.columns.map(c => String(c).substring(0, colWidth - 2).padEnd(colWidth)).join('│ ')} ◀ HEADERS`;
|
|
913
993
|
lines.push(headerLine);
|
|
914
|
-
lines.push('
|
|
994
|
+
lines.push(`${'───'.padEnd(idxWidth)}${'─'.repeat(Math.min(colWidth * df.columns.length, 120))}`);
|
|
915
995
|
|
|
916
996
|
const dataRows = df.toRows();
|
|
917
997
|
dataRows.forEach((row, i) => {
|
|
918
|
-
const rowIdx =
|
|
919
|
-
const cols = Object.values(row).map(v => String(v ?? '').substring(0, colWidth - 2).padEnd(colWidth)).join('
|
|
998
|
+
const rowIdx = `[${totalOffset + 1 + i}]`.padEnd(idxWidth);
|
|
999
|
+
const cols = Object.values(row).map(v => String(v ?? '').substring(0, colWidth - 2).padEnd(colWidth)).join('│ ');
|
|
920
1000
|
lines.push(`${rowIdx}${cols}`);
|
|
921
1001
|
});
|
|
922
1002
|
|
package/lib/styles/shadcn.css
CHANGED
|
@@ -589,49 +589,47 @@ code {
|
|
|
589
589
|
.jux-modal-position-fullscreen .jux-modal { width: 100%; max-width: 100%; height: 100vh; max-height: 100vh; border-radius: 0; }
|
|
590
590
|
|
|
591
591
|
/* ═══════════════════════════════════════════════════════════════════
|
|
592
|
-
*
|
|
592
|
+
* DATAFRAME TAB SETTINGS COG
|
|
593
593
|
* ═══════════════════════════════════════════════════════════════════ */
|
|
594
594
|
|
|
595
|
-
.jux-
|
|
596
|
-
|
|
595
|
+
.jux-dataframe-tab-settings {
|
|
596
|
+
display: inline-flex;
|
|
597
|
+
align-items: center;
|
|
598
|
+
justify-content: center;
|
|
599
|
+
background: transparent;
|
|
600
|
+
border: none;
|
|
601
|
+
padding: 0.125rem;
|
|
602
|
+
margin-left: 0.375rem;
|
|
603
|
+
border-radius: 0.25rem;
|
|
604
|
+
cursor: pointer;
|
|
597
605
|
color: hsl(var(--muted-foreground));
|
|
598
|
-
|
|
599
|
-
|
|
600
|
-
background: hsl(var(--warning) / 0.08);
|
|
601
|
-
border-radius: var(--radius);
|
|
602
|
-
border: 1px solid hsl(var(--warning) / 0.2);
|
|
603
|
-
line-height: 1.5;
|
|
606
|
+
opacity: 0.5;
|
|
607
|
+
transition: all 0.15s;
|
|
604
608
|
}
|
|
605
609
|
|
|
606
|
-
.jux-
|
|
610
|
+
.jux-dataframe-tab-settings:hover {
|
|
611
|
+
opacity: 1;
|
|
612
|
+
background: hsl(var(--muted) / 0.5);
|
|
607
613
|
color: hsl(var(--foreground));
|
|
608
614
|
}
|
|
609
615
|
|
|
610
|
-
.jux-
|
|
611
|
-
|
|
612
|
-
border-radius: var(--radius);
|
|
613
|
-
padding: 1rem;
|
|
614
|
-
background: hsl(var(--muted) / 0.3);
|
|
615
|
-
max-height: 400px;
|
|
616
|
-
overflow: auto;
|
|
616
|
+
.jux-tabs-button-active .jux-dataframe-tab-settings {
|
|
617
|
+
opacity: 0.7;
|
|
617
618
|
}
|
|
618
619
|
|
|
619
|
-
.jux-
|
|
620
|
-
|
|
621
|
-
font-size: 0.6875rem;
|
|
622
|
-
white-space: pre;
|
|
623
|
-
color: hsl(var(--foreground));
|
|
624
|
-
line-height: 1.6;
|
|
625
|
-
tab-size: 4;
|
|
620
|
+
.jux-tabs-button-active .jux-dataframe-tab-settings:hover {
|
|
621
|
+
opacity: 1;
|
|
626
622
|
}
|
|
627
623
|
|
|
628
|
-
/*
|
|
629
|
-
|
|
630
|
-
|
|
624
|
+
/* Make tabs list scrollable if many sheets */
|
|
625
|
+
.jux-dataframe-tabs .jux-tabs-list {
|
|
626
|
+
overflow-x: auto;
|
|
627
|
+
flex-wrap: nowrap;
|
|
628
|
+
max-width: 100%;
|
|
629
|
+
}
|
|
631
630
|
|
|
632
|
-
.jux-
|
|
633
|
-
|
|
634
|
-
|
|
635
|
-
|
|
636
|
-
border-radius: calc(var(--radius) - 2px);
|
|
631
|
+
.jux-dataframe-tabs .jux-tabs-button {
|
|
632
|
+
display: inline-flex;
|
|
633
|
+
align-items: center;
|
|
634
|
+
flex-shrink: 0;
|
|
637
635
|
}
|