feat(tsview): add database and S3 handlers, tswatch/watch scripts, web utilities, assets and release config
This commit is contained in:
@@ -1,5 +1,7 @@
|
||||
import * as plugins from '../plugins.js';
|
||||
import { apiService } from '../services/index.js';
|
||||
import { formatSize, getFileName } from '../utilities/index.js';
|
||||
import { themeStyles } from '../styles/index.js';
|
||||
|
||||
const { html, css, cssManager, customElement, property, state, DeesElement } = plugins;
|
||||
|
||||
@@ -31,6 +33,7 @@ export class TsviewS3Preview extends DeesElement {
|
||||
|
||||
public static styles = [
|
||||
cssManager.defaultStyles,
|
||||
themeStyles,
|
||||
css`
|
||||
:host {
|
||||
display: block;
|
||||
@@ -104,9 +107,9 @@ export class TsviewS3Preview extends DeesElement {
|
||||
.action-btn {
|
||||
flex: 1;
|
||||
padding: 8px 16px;
|
||||
background: rgba(99, 102, 241, 0.2);
|
||||
border: 1px solid #6366f1;
|
||||
color: #818cf8;
|
||||
background: rgba(255, 255, 255, 0.1);
|
||||
border: 1px solid #404040;
|
||||
color: #e0e0e0;
|
||||
border-radius: 6px;
|
||||
cursor: pointer;
|
||||
font-size: 13px;
|
||||
@@ -114,7 +117,7 @@ export class TsviewS3Preview extends DeesElement {
|
||||
}
|
||||
|
||||
.action-btn:hover {
|
||||
background: rgba(99, 102, 241, 0.3);
|
||||
background: rgba(255, 255, 255, 0.15);
|
||||
}
|
||||
|
||||
.action-btn.danger {
|
||||
@@ -174,6 +177,7 @@ export class TsviewS3Preview extends DeesElement {
|
||||
} else {
|
||||
this.content = '';
|
||||
this.contentType = '';
|
||||
this.error = ''; // Clear error when no file selected
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -198,22 +202,6 @@ export class TsviewS3Preview extends DeesElement {
|
||||
this.loading = false;
|
||||
}
|
||||
|
||||
private getFileName(path: string): string {
|
||||
const parts = path.split('/');
|
||||
return parts[parts.length - 1] || path;
|
||||
}
|
||||
|
||||
private formatSize(bytes: number): string {
|
||||
const units = ['B', 'KB', 'MB', 'GB', 'TB'];
|
||||
let size = bytes;
|
||||
let unitIndex = 0;
|
||||
while (size >= 1024 && unitIndex < units.length - 1) {
|
||||
size /= 1024;
|
||||
unitIndex++;
|
||||
}
|
||||
return `${size.toFixed(unitIndex > 0 ? 1 : 0)} ${units[unitIndex]}`;
|
||||
}
|
||||
|
||||
private formatDate(dateStr: string): string {
|
||||
if (!dateStr) return '-';
|
||||
const date = new Date(dateStr);
|
||||
@@ -235,7 +223,13 @@ export class TsviewS3Preview extends DeesElement {
|
||||
|
||||
private getTextContent(): string {
|
||||
try {
|
||||
return atob(this.content);
|
||||
// Properly decode base64 to UTF-8 text
|
||||
const binaryString = atob(this.content);
|
||||
const bytes = new Uint8Array(binaryString.length);
|
||||
for (let i = 0; i < binaryString.length; i++) {
|
||||
bytes[i] = binaryString.charCodeAt(i);
|
||||
}
|
||||
return new TextDecoder('utf-8').decode(bytes);
|
||||
} catch {
|
||||
return 'Unable to decode content';
|
||||
}
|
||||
@@ -249,7 +243,7 @@ export class TsviewS3Preview extends DeesElement {
|
||||
const url = URL.createObjectURL(blob);
|
||||
const a = document.createElement('a');
|
||||
a.href = url;
|
||||
a.download = this.getFileName(this.objectKey);
|
||||
a.download = getFileName(this.objectKey);
|
||||
document.body.appendChild(a);
|
||||
a.click();
|
||||
document.body.removeChild(a);
|
||||
@@ -260,7 +254,7 @@ export class TsviewS3Preview extends DeesElement {
|
||||
}
|
||||
|
||||
private async handleDelete() {
|
||||
if (!confirm(`Delete "${this.getFileName(this.objectKey)}"?`)) return;
|
||||
if (!confirm(`Delete "${getFileName(this.objectKey)}"?`)) return;
|
||||
|
||||
try {
|
||||
await apiService.deleteObject(this.bucketName, this.objectKey);
|
||||
@@ -310,10 +304,10 @@ export class TsviewS3Preview extends DeesElement {
|
||||
return html`
|
||||
<div class="preview-container">
|
||||
<div class="preview-header">
|
||||
<div class="preview-title">${this.getFileName(this.objectKey)}</div>
|
||||
<div class="preview-title">${getFileName(this.objectKey)}</div>
|
||||
<div class="preview-meta">
|
||||
<span class="meta-item">${this.contentType}</span>
|
||||
<span class="meta-item">${this.formatSize(this.size)}</span>
|
||||
<span class="meta-item">${formatSize(this.size)}</span>
|
||||
<span class="meta-item">${this.formatDate(this.lastModified)}</span>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
Reference in New Issue
Block a user