fix(export): enable proper file downloads and fix empty PNG export
This commit is contained in:
@@ -223,14 +223,14 @@ import Tooltip from "../components/Tooltip.astro";
|
||||
<TuiButton
|
||||
id="btn-copy-text"
|
||||
label="TXT"
|
||||
title="Copy Text"
|
||||
description="Copy raw ASCII text to clipboard."
|
||||
title="Save as Text"
|
||||
description="Download raw ASCII text file."
|
||||
/>
|
||||
<TuiButton
|
||||
id="btn-copy-html"
|
||||
label="HTML"
|
||||
title="Copy HTML"
|
||||
description="Copy colored HTML span elements to clipboard."
|
||||
title="Save as HTML"
|
||||
description="Download colored HTML file."
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -417,11 +417,27 @@ export class AsciiController {
|
||||
// ============= Export =============
|
||||
|
||||
savePNG(): void {
|
||||
const timestamp = new Date().toISOString().replace(/[:.]/g, '-').slice(0, 19);
|
||||
AsciiExporter.downloadPNG(this.canvas, `ascii-art-${timestamp}.png`);
|
||||
const wasShowing = this.zoomState.showMagnifier;
|
||||
|
||||
// 1. Force hide magnifier for clean export
|
||||
if (wasShowing) {
|
||||
this.zoomState.showMagnifier = false;
|
||||
this.requestRender('uniforms');
|
||||
// Force synchronous render
|
||||
this.renderFrame();
|
||||
}
|
||||
|
||||
async copyText(): Promise<void> {
|
||||
const timestamp = new Date().toISOString().replace(/[:.]/g, '-').slice(0, 19);
|
||||
AsciiExporter.downloadPNG(this.canvas, `ascii-art-${timestamp}.png`);
|
||||
|
||||
// 2. Restore state
|
||||
if (wasShowing) {
|
||||
this.zoomState.showMagnifier = true;
|
||||
this.requestRender('uniforms');
|
||||
}
|
||||
}
|
||||
|
||||
saveText(): void {
|
||||
if (!this.cachedGrid.imgEl) return;
|
||||
const text = AsciiExporter.generateText(
|
||||
this.cachedGrid.imgEl,
|
||||
@@ -429,10 +445,11 @@ export class AsciiController {
|
||||
this.cachedGrid.widthCols,
|
||||
Math.floor(this.cachedGrid.heightRows)
|
||||
);
|
||||
await AsciiExporter.copyToClipboard(text);
|
||||
const timestamp = new Date().toISOString().replace(/[:.]/g, '-').slice(0, 19);
|
||||
AsciiExporter.downloadText(text, `ascii-art-${timestamp}.txt`);
|
||||
}
|
||||
|
||||
async copyHTML(): Promise<void> {
|
||||
saveHTML(): void {
|
||||
if (!this.cachedGrid.imgEl) return;
|
||||
const html = AsciiExporter.generateHTML(
|
||||
this.cachedGrid.imgEl,
|
||||
@@ -440,7 +457,8 @@ export class AsciiController {
|
||||
this.cachedGrid.widthCols,
|
||||
Math.floor(this.cachedGrid.heightRows)
|
||||
);
|
||||
await AsciiExporter.copyToClipboard(html);
|
||||
const timestamp = new Date().toISOString().replace(/[:.]/g, '-').slice(0, 19);
|
||||
AsciiExporter.downloadText(html, `ascii-art-${timestamp}.html`);
|
||||
}
|
||||
|
||||
// ============= Utilities =============
|
||||
|
||||
@@ -8,6 +8,15 @@ export class AsciiExporter {
|
||||
link.click();
|
||||
}
|
||||
|
||||
static downloadText(content: string, filename: string) {
|
||||
const blob = new Blob([content], { type: 'text/plain;charset=utf-8' });
|
||||
const link = document.createElement('a');
|
||||
link.href = URL.createObjectURL(blob);
|
||||
link.download = filename;
|
||||
link.click();
|
||||
URL.revokeObjectURL(link.href);
|
||||
}
|
||||
|
||||
static async copyToClipboard(text: string): Promise<void> {
|
||||
if (navigator.clipboard && navigator.clipboard.writeText) {
|
||||
await navigator.clipboard.writeText(text);
|
||||
|
||||
@@ -308,9 +308,9 @@ export class UIBindings {
|
||||
|
||||
const btnCopyText = document.getElementById('btn-copy-text');
|
||||
if (btnCopyText) {
|
||||
const handler = async (e: Event) => {
|
||||
const handler = (e: Event) => {
|
||||
e.stopPropagation();
|
||||
await this.controller.copyText();
|
||||
this.controller.saveText();
|
||||
};
|
||||
this.buttonHandlers.set('btn-copy-text', handler);
|
||||
btnCopyText.addEventListener('click', handler);
|
||||
@@ -318,9 +318,9 @@ export class UIBindings {
|
||||
|
||||
const btnCopyHtml = document.getElementById('btn-copy-html');
|
||||
if (btnCopyHtml) {
|
||||
const handler = async (e: Event) => {
|
||||
const handler = (e: Event) => {
|
||||
e.stopPropagation();
|
||||
await this.controller.copyHTML();
|
||||
this.controller.saveHTML();
|
||||
};
|
||||
this.buttonHandlers.set('btn-copy-html', handler);
|
||||
btnCopyHtml.addEventListener('click', handler);
|
||||
|
||||
@@ -46,7 +46,7 @@ export class WebGLAsciiRenderer {
|
||||
private lastImage: HTMLImageElement | null;
|
||||
|
||||
constructor(_canvas: HTMLCanvasElement) {
|
||||
const gl = _canvas.getContext('webgl', { antialias: false });
|
||||
const gl = _canvas.getContext('webgl', { antialias: false, preserveDrawingBuffer: true });
|
||||
if (!gl) {
|
||||
throw new Error('WebGL not supported');
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user