feat: Add preview fit mode for height and utilize Vega-Lite's 'container' keyword for dynamic sizing.

This commit is contained in:
2025-12-09 23:28:36 +02:00
parent 00ccdd27d5
commit 3f6c3b69a6
3 changed files with 53 additions and 50 deletions

View File

@@ -233,6 +233,10 @@
@click="$store.preview.fitMode = 'width'; setPreviewFitMode('width')"
id="preview-fit-width"
title="Scale to fit preview pane width (⚠️ for faceted specs, applies to each facet)">Width</button>
<button class="btn btn-toggle" :class="{ 'active': $store.preview.fitMode === 'height' }"
@click="$store.preview.fitMode = 'height'; setPreviewFitMode('height')"
id="preview-fit-height"
title="Scale to fit preview pane height (⚠️ for faceted specs, applies to each facet)">Height</button>
<button class="btn btn-toggle" :class="{ 'active': $store.preview.fitMode === 'full' }"
@click="$store.preview.fitMode = 'full'; setPreviewFitMode('full')"
id="preview-fit-full"
@@ -308,12 +312,13 @@
</div>
<div class="dataset-detail-header">Name</div>
<input type="text" id="dataset-detail-name" class="input"
placeholder="Dataset name..." :value="dataset?.name" @input="handleNameChange" />
<input type="text" id="dataset-detail-name" class="input" placeholder="Dataset name..."
:value="dataset?.name" @input="handleNameChange" />
<div class="dataset-detail-header">Comment</div>
<textarea id="dataset-detail-comment" class="input textarea"
placeholder="Add a comment..." rows="3" :value="dataset?.comment" @input="handleCommentChange"></textarea>
placeholder="Add a comment..." rows="3" :value="dataset?.comment"
@input="handleCommentChange"></textarea>
<div class="dataset-detail-header-row">
<span class="dataset-detail-header">Overview</span>
@@ -344,7 +349,8 @@
<div class="columns-list">
<template x-for="col in dataset?.columnTypes" :key="col.name">
<div class="column-item">
<span class="column-type-icon" x-html="getTypeIcon(col.type)"></span>
<span class="column-type-icon"
x-html="getTypeIcon(col.type)"></span>
<span class="column-name" x-text="col.name"></span>
<span class="column-type" x-text="col.type"></span>
</div>
@@ -361,7 +367,8 @@
</div>
<div class="stat-item">
<span class="stat-label">Modified:</span>
<span id="dataset-detail-modified" x-text="formatDate(dataset?.modified)">-</span>
<span id="dataset-detail-modified"
x-text="formatDate(dataset?.modified)">-</span>
</div>
</div>
</div>
@@ -372,8 +379,7 @@
<div class="preview-toggle-group" x-show="showPreviewToggle">
<button class="btn btn-toggle small"
:class="{ 'active': $store.datasets.previewMode === 'raw' }"
@click="setPreviewMode('raw')"
title="Show raw data preview">Raw</button>
@click="setPreviewMode('raw')" title="Show raw data preview">Raw</button>
<button class="btn btn-toggle small"
:class="{ 'active': $store.datasets.previewMode === 'table' }"
@click="setPreviewMode('table')"
@@ -394,7 +400,7 @@
<span class="stat-label">📄</span>
<span>
<a href="#" @click.prevent="openLinkedSnippet(snippet.id)"
class="snippet-link" x-text="snippet.name"></a>
class="snippet-link" x-text="snippet.name"></a>
</span>
</div>
</template>

View File

@@ -190,7 +190,7 @@ document.addEventListener('alpine:init', () => {
// Preview panel fit mode store
Alpine.store('preview', {
fitMode: 'default' // 'default' | 'width' | 'full'
fitMode: 'default' // 'default' | 'width' | 'height' | 'full'
});
});

View File

@@ -1,56 +1,53 @@
// Track preview fit mode
let previewFitMode = 'default'; // 'default', 'width', or 'full'
let previewFitMode = 'default'; // 'default', 'width', 'height', or 'full'
// Apply fit mode to spec dimensions
// Apply fit mode to spec dimensions using Vega-Lite's "container" keyword
function applyPreviewFitMode(spec, fitMode) {
if (!spec || typeof spec !== 'object') return spec;
// Clone to avoid mutation
const modifiedSpec = JSON.parse(JSON.stringify(spec));
if (fitMode === 'width' || fitMode === 'full') {
const previewPane = document.getElementById('vega-preview');
if (previewPane) {
const containerWidth = previewPane.offsetWidth - 10; // 10px padding for scroll
const containerHeight = previewPane.offsetHeight - 10; // 10px padding
// Apply dimensions recursively to handle nested specs
function applyDimensions(s) {
if (!s || typeof s !== 'object') return;
// Apply dimensions recursively to handle nested specs
function applyDimensions(s) {
if (!s || typeof s !== 'object') return;
// Apply dimensions based on fit mode
if (fitMode === 'width') {
s.width = 'container';
delete s.height; // Remove height to preserve aspect ratio
} else if (fitMode === 'height') {
s.height = 'container';
delete s.width; // Remove width to preserve aspect ratio
} else if (fitMode === 'full') {
s.width = 'container';
s.height = 'container';
}
// 'default' mode leaves original dimensions untouched
// Set dimensions at current level if this is a unit spec or has width/height
if (fitMode === 'width') {
s.width = containerWidth;
delete s.height; // Remove height to preserve aspect ratio
} else if (fitMode === 'full') {
s.width = containerWidth;
s.height = containerHeight;
}
// Recursively apply to nested specs
// For facet specs
if (s.spec) {
applyDimensions(s.spec);
}
// For layer, concat, hconcat, vconcat
if (Array.isArray(s.layer)) {
s.layer.forEach(applyDimensions);
}
if (Array.isArray(s.concat)) {
s.concat.forEach(applyDimensions);
}
if (Array.isArray(s.hconcat)) {
s.hconcat.forEach(applyDimensions);
}
if (Array.isArray(s.vconcat)) {
s.vconcat.forEach(applyDimensions);
}
}
applyDimensions(modifiedSpec);
// Recursively apply to nested specs
// For facet specs
if (s.spec) {
applyDimensions(s.spec);
}
// For layer, concat, hconcat, vconcat
if (Array.isArray(s.layer)) {
s.layer.forEach(applyDimensions);
}
if (Array.isArray(s.concat)) {
s.concat.forEach(applyDimensions);
}
if (Array.isArray(s.hconcat)) {
s.hconcat.forEach(applyDimensions);
}
if (Array.isArray(s.vconcat)) {
s.vconcat.forEach(applyDimensions);
}
}
// 'default' mode leaves original dimensions untouched
if (fitMode !== 'default') {
applyDimensions(modifiedSpec);
}
return modifiedSpec;
}