diff --git a/.changeset/hungry-jokes-say.md b/.changeset/hungry-jokes-say.md new file mode 100644 index 0000000..684f3e2 --- /dev/null +++ b/.changeset/hungry-jokes-say.md @@ -0,0 +1,5 @@ +--- +"sqlseal-charts": patch +--- + +now every chart can be opened in full screen diff --git a/src/chartRenderer.ts b/src/chartRenderer.ts index 9d1ae5f..6f915ee 100644 --- a/src/chartRenderer.ts +++ b/src/chartRenderer.ts @@ -1,4 +1,4 @@ -import { App } from "obsidian"; +import { App, setIcon } from "obsidian"; import { parseCode } from "./utils/configParser"; import { prepareDataVariables } from "./utils/prepareDataVariables"; import * as echarts from 'echarts'; @@ -6,6 +6,7 @@ import * as ecStat from 'echarts-stat'; import type { RendererConfig } from "@hypersphere/sqlseal"; import { ViewDefinition } from "@hypersphere/sqlseal/dist/src/grammar/parser"; import { parseCodeAdvanced } from "./utils/advancedParser"; +import { FullScreenChartModal } from "./fullscreenModal"; interface Config { config: string @@ -36,6 +37,20 @@ export class ChartRenderer implements RendererConfig { return { config: config.trim() } } + private createFullscreenButton(container: HTMLElement, chartConfig: Record) { + const fullscreenButton = container.createEl('button', { + cls: 'sqlseal-fullscreen-button', + attr: { 'aria-label': 'Open chart in fullscreen' } + }) + setIcon(fullscreenButton, 'maximize-2') + + fullscreenButton.addEventListener('click', (e) => { + e.stopPropagation(); + const modal = new FullScreenChartModal(this.app, chartConfig); + modal.open(); + }) + } + render(config: Config, el: HTMLElement) { let isRendered: boolean = false let chart: echarts.ECharts | null = null @@ -78,12 +93,16 @@ export class ChartRenderer implements RendererConfig { el.empty() const container = el.createDiv({ cls: 'sqlseal-charts-container' }) - const chartDiv = container.createDiv() + + const chartHeader = container.createDiv({ cls: 'sqlseal-chart-header' }) + const chartDiv = container.createDiv({ cls: 'sqlseal-chart-content' }) + + this.createFullscreenButton(chartHeader, configRecord) requestAnimationFrame(() => { - const box = container.getBoundingClientRect() - const width = box.width - const height = box.height + const containerBox = container.getBoundingClientRect() + const width = containerBox.width + const height = containerBox.height chart = echarts.init(chartDiv, null, { height: height, width: width }) chart.setOption(configRecord) isRendered = true diff --git a/src/fullscreenModal.ts b/src/fullscreenModal.ts new file mode 100644 index 0000000..9df3a39 --- /dev/null +++ b/src/fullscreenModal.ts @@ -0,0 +1,87 @@ +import { App, Modal } from "obsidian"; +import * as echarts from 'echarts'; + +export class FullScreenChartModal extends Modal { + private chart: echarts.ECharts | null = null; + private chartConfig: Record; + private resizeHandler: (() => void) | null = null; + + constructor(app: App, chartConfig: Record) { + super(app); + this.chartConfig = chartConfig; + + this.scope.register([], "Escape", () => { + this.close(); + }); + } + + onOpen() { + const { contentEl, modalEl } = this; + contentEl.empty(); + + // Apply fullscreen classes + modalEl.addClass('sqlseal-fullscreen-modal'); + contentEl.addClass('sqlseal-fullscreen-modal'); + + // Force modal to fullscreen dimensions + modalEl.style.width = '100vw'; + modalEl.style.height = '100vh'; + modalEl.style.maxWidth = 'none'; + modalEl.style.maxHeight = 'none'; + modalEl.style.left = '0'; + modalEl.style.top = '0'; + modalEl.style.transform = 'none'; + modalEl.style.margin = '0'; + + // Set content area dimensions + contentEl.style.width = '95vw'; + contentEl.style.height = '90vh'; + contentEl.style.maxWidth = 'none'; + contentEl.style.maxHeight = 'none'; + contentEl.style.margin = '2.5vh 2.5vw'; + contentEl.style.position = 'absolute'; + contentEl.style.left = '2.5vw'; + contentEl.style.top = '5vh'; + + const chartContainer = contentEl.createDiv({ cls: 'sqlseal-fullscreen-chart-container' }); + + // Initialize chart after modal is rendered + requestAnimationFrame(() => { + requestAnimationFrame(() => { + const containerRect = chartContainer.getBoundingClientRect(); + + const width = containerRect.width || window.innerWidth * 0.9; + const height = containerRect.height || window.innerHeight * 0.8; + + this.chart = echarts.init(chartContainer, null, { width, height }); + this.chart.setOption(this.chartConfig); + + this.resizeHandler = () => { + if (this.chart) { + this.chart.resize(); + } + }; + + window.addEventListener('resize', this.resizeHandler); + + // Ensure proper sizing after initialization + setTimeout(() => { + if (this.chart) { + this.chart.resize(); + } + }, 100); + }); + }); + } + + onClose() { + if (this.resizeHandler) { + window.removeEventListener('resize', this.resizeHandler); + this.resizeHandler = null; + } + if (this.chart) { + this.chart.dispose(); + this.chart = null; + } + } +} \ No newline at end of file diff --git a/styles.css b/styles.css index 7e497fa..8db2c18 100644 --- a/styles.css +++ b/styles.css @@ -1,11 +1,69 @@ .sqlseal-charts-container { - display: grid; - justify-content: center; + display: flex; + flex-direction: column; width: 100%; aspect-ratio: 16 / 9; + position: relative; } -.sqlseal-charts-container > div { +.sqlseal-chart-header { + display: flex; + justify-content: flex-end; + position: absolute; + bottom: 8px; + right: 8px; + z-index: 10; +} + +.sqlseal-fullscreen-button { + background: var(--background-modifier-hover); + border: none; + border-radius: var(--radius-s); + padding: 4px; + cursor: pointer; + display: flex; + align-items: center; + justify-content: center; + opacity: 0.7; + transition: opacity 0.2s ease; +} + +.sqlseal-fullscreen-button:hover { + background: var(--background-modifier-border-hover); + opacity: 1; +} + +.sqlseal-chart-content { width: 100%; height: 100%; + flex: 1; +} + +.sqlseal-fullscreen-modal { + z-index: 9999; +} + +.sqlseal-fullscreen-modal .modal { + width: 100vw !important; + height: 100vh !important; + max-width: none !important; + max-height: none !important; + margin: 0 !important; + padding: 0 !important; +} + +.sqlseal-fullscreen-modal .modal-content { + width: 95vw !important; + height: 90vh !important; + max-width: none !important; + max-height: none !important; + padding: 20px !important; + margin: 2.5vh 2.5vw !important; + border-radius: 8px !important; +} + +.sqlseal-fullscreen-chart-container { + width: 100%; + height: calc(90vh - 40px); + min-height: 400px; } \ No newline at end of file