Compare commits
2 Commits
@@ -631,6 +631,11 @@ data: [DONE]
|
|||||||
|
|
||||||
## Changelog
|
## Changelog
|
||||||
|
|
||||||
|
### v3.3.1 (2026-05-21)
|
||||||
|
- **HTML Preview** — HTML code blocks no longer render inside chat and break the flow
|
||||||
|
- Added sandboxed iframe preview panel with Preview button
|
||||||
|
- Added Open in Browser button for full-screen HTML preview
|
||||||
|
|
||||||
### v3.3.0 (2026-05-21)
|
### v3.3.0 (2026-05-21)
|
||||||
- **File Manager** — browse device files (App Files, Downloads, Camera, Storage), open/preview any file, install APKs directly
|
- **File Manager** — browse device files (App Files, Downloads, Camera, Storage), open/preview any file, install APKs directly
|
||||||
- **SSH / Remote Access** — AI can SSH into external machines, SCP upload/download, curl URLs
|
- **SSH / Remote Access** — AI can SSH into external machines, SCP upload/download, curl URLs
|
||||||
|
|||||||
@@ -21,8 +21,8 @@ android {
|
|||||||
applicationId "ai.z.chat"
|
applicationId "ai.z.chat"
|
||||||
minSdkVersion rootProject.ext.minSdkVersion
|
minSdkVersion rootProject.ext.minSdkVersion
|
||||||
targetSdkVersion rootProject.ext.targetSdkVersion
|
targetSdkVersion rootProject.ext.targetSdkVersion
|
||||||
versionCode 25
|
versionCode 26
|
||||||
versionName "3.3.0"
|
versionName "3.3.1"
|
||||||
testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
|
testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
|
||||||
aaptOptions {
|
aaptOptions {
|
||||||
ignoreAssetsPattern = '!.svn:!.git:!.ds_store:!*.scc:.*:!CVS:!thumbs.db:!picasa.ini:!*~'
|
ignoreAssetsPattern = '!.svn:!.git:!.ds_store:!*.scc:.*:!CVS:!thumbs.db:!picasa.ini:!*~'
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "zai-chat",
|
"name": "zai-chat",
|
||||||
"version": "3.3.0",
|
"version": "3.3.1",
|
||||||
"description": "Z.AI Chat - Full stack AI chat powered by GLM Coding Plan",
|
"description": "Z.AI Chat - Full stack AI chat powered by GLM Coding Plan",
|
||||||
"main": "index.js",
|
"main": "index.js",
|
||||||
"scripts": {
|
"scripts": {
|
||||||
|
|||||||
@@ -431,6 +431,33 @@ a:hover { text-decoration: underline; }
|
|||||||
}
|
}
|
||||||
.copy-btn:hover, .download-btn:hover { background: var(--accent); color: white; }
|
.copy-btn:hover, .download-btn:hover { background: var(--accent); color: white; }
|
||||||
|
|
||||||
|
.html-preview-block { margin: 8px 0; }
|
||||||
|
.html-preview-bar {
|
||||||
|
display: flex;
|
||||||
|
justify-content: space-between;
|
||||||
|
align-items: center;
|
||||||
|
padding: 6px 12px;
|
||||||
|
background: var(--bg-tertiary);
|
||||||
|
border-radius: 8px 8px 0 0;
|
||||||
|
font-size: 12px;
|
||||||
|
color: var(--text-secondary);
|
||||||
|
border: 1px solid var(--border);
|
||||||
|
border-bottom: none;
|
||||||
|
}
|
||||||
|
.html-preview-bar + pre { border-top-left-radius: 0; border-top-right-radius: 0; }
|
||||||
|
.html-preview-btn {
|
||||||
|
background: linear-gradient(135deg, #6c63ff, #a855f7);
|
||||||
|
border: none;
|
||||||
|
color: white;
|
||||||
|
padding: 4px 14px;
|
||||||
|
border-radius: 4px;
|
||||||
|
font-size: 11px;
|
||||||
|
font-weight: 600;
|
||||||
|
cursor: pointer;
|
||||||
|
transition: opacity var(--transition);
|
||||||
|
}
|
||||||
|
.html-preview-btn:hover { opacity: 0.85; }
|
||||||
|
|
||||||
.msg-actions {
|
.msg-actions {
|
||||||
display: flex;
|
display: flex;
|
||||||
gap: 6px;
|
gap: 6px;
|
||||||
|
|||||||
@@ -132,6 +132,19 @@
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
<div id="html-preview" class="file-viewer" style="display:none;z-index:2500;">
|
||||||
|
<div class="file-viewer-header">
|
||||||
|
<div class="file-viewer-title">
|
||||||
|
<span id="html-preview-title">HTML Preview</span>
|
||||||
|
</div>
|
||||||
|
<div class="file-viewer-actions">
|
||||||
|
<button id="html-preview-newtab" class="fv-btn">Open in Browser</button>
|
||||||
|
<button id="html-preview-close" class="icon-btn" aria-label="Close preview">×</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<iframe id="html-preview-frame" sandbox="allow-scripts allow-same-origin" style="flex:1;width:100%;border:none;background:white;border-radius:0 0 12px 12px;"></iframe>
|
||||||
|
</div>
|
||||||
|
|
||||||
<div id="messages" class="messages"></div>
|
<div id="messages" class="messages"></div>
|
||||||
|
|
||||||
<div id="terminal-panel" class="terminal-panel">
|
<div id="terminal-panel" class="terminal-panel">
|
||||||
@@ -341,7 +354,7 @@
|
|||||||
</div>
|
</div>
|
||||||
<div class="settings-section">
|
<div class="settings-section">
|
||||||
<h3>About</h3>
|
<h3>About</h3>
|
||||||
<p class="about-text">Z.AI Chat v3.3.0</p>
|
<p class="about-text">Z.AI Chat v3.3.1</p>
|
||||||
<p class="about-text">Built with Z.AI SDK & GLM-5.1</p>
|
<p class="about-text">Built with Z.AI SDK & GLM-5.1</p>
|
||||||
<p class="about-text">Compatible with Android 15/16</p>
|
<p class="about-text">Compatible with Android 15/16</p>
|
||||||
</div>
|
</div>
|
||||||
@@ -349,6 +362,11 @@
|
|||||||
<h3>Changelog</h3>
|
<h3>Changelog</h3>
|
||||||
<ul class="changelog-list">
|
<ul class="changelog-list">
|
||||||
<li>
|
<li>
|
||||||
|
<span class="changelog-version">v3.3.1</span>
|
||||||
|
<span class="changelog-date">2026-05-21</span>
|
||||||
|
<ul>
|
||||||
|
<li><strong>HTML Preview</strong> — HTML code blocks no longer break chat; sandboxed iframe preview with Open in Browser</li>
|
||||||
|
</ul>
|
||||||
<span class="changelog-version">v3.3.0</span>
|
<span class="changelog-version">v3.3.0</span>
|
||||||
<span class="changelog-date">2026-05-21</span>
|
<span class="changelog-date">2026-05-21</span>
|
||||||
<ul>
|
<ul>
|
||||||
|
|||||||
@@ -330,9 +330,20 @@
|
|||||||
return code;
|
return code;
|
||||||
},
|
},
|
||||||
breaks: true,
|
breaks: true,
|
||||||
gfm: true
|
gfm: true,
|
||||||
|
sanitize: false
|
||||||
});
|
});
|
||||||
return marked.parse(text);
|
var html = marked.parse(text);
|
||||||
|
html = html.replace(/<pre><code class="language-html">([\s\S]*?)<\/code><\/pre>/gi, function(match, codeContent) {
|
||||||
|
var decoded = codeContent.replace(/</g, '<').replace(/>/g, '>').replace(/&/g, '&').replace(/"/g, '"').replace(/'/g, "'");
|
||||||
|
var uid = 'hprev_' + Math.random().toString(36).substr(2, 9);
|
||||||
|
return '<div class="html-preview-block" data-uid="' + uid + '">' +
|
||||||
|
'<div class="html-preview-bar"><span>HTML</span><button class="html-preview-btn" data-uid="' + uid + '">Preview</button></div>' +
|
||||||
|
'<pre><code class="language-html">' + codeContent + '</code></pre>' +
|
||||||
|
'<textarea class="html-preview-src" style="display:none">' + escapeHtml(decoded) + '</textarea>' +
|
||||||
|
'</div>';
|
||||||
|
});
|
||||||
|
return html;
|
||||||
}
|
}
|
||||||
return text.replace(/</g, '<').replace(/>/g, '>').replace(/\n/g, '<br>');
|
return text.replace(/</g, '<').replace(/>/g, '>').replace(/\n/g, '<br>');
|
||||||
}
|
}
|
||||||
@@ -405,6 +416,43 @@
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
container.querySelectorAll('.html-preview-btn').forEach(function(btn) {
|
||||||
|
btn.addEventListener('click', function() {
|
||||||
|
var uid = this.getAttribute('data-uid');
|
||||||
|
var wrapper = container.querySelector('.html-preview-block[data-uid="' + uid + '"]');
|
||||||
|
if (!wrapper) return;
|
||||||
|
var srcEl = wrapper.querySelector('.html-preview-src');
|
||||||
|
if (!srcEl) return;
|
||||||
|
var src = srcEl.textContent;
|
||||||
|
openHtmlPreview(src);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
function openHtmlPreview(htmlSource) {
|
||||||
|
var preview = $('#html-preview');
|
||||||
|
var frame = $('#html-preview-frame');
|
||||||
|
var title = $('#html-preview-title');
|
||||||
|
if (!preview || !frame) return;
|
||||||
|
if (title) title.textContent = 'HTML Preview';
|
||||||
|
preview.style.display = 'flex';
|
||||||
|
var doc = frame.contentDocument || frame.contentWindow.document;
|
||||||
|
doc.open();
|
||||||
|
doc.write(htmlSource);
|
||||||
|
doc.close();
|
||||||
|
}
|
||||||
|
|
||||||
|
function closeHtmlPreview() {
|
||||||
|
var preview = $('#html-preview');
|
||||||
|
if (preview) preview.style.display = 'none';
|
||||||
|
}
|
||||||
|
|
||||||
|
function openHtmlInNewTab(htmlSource) {
|
||||||
|
var blob = new Blob([htmlSource], { type: 'text/html' });
|
||||||
|
var url = URL.createObjectURL(blob);
|
||||||
|
window.open(url, '_blank');
|
||||||
|
setTimeout(function() { URL.revokeObjectURL(url); }, 60000);
|
||||||
}
|
}
|
||||||
|
|
||||||
function highlightFilePaths(html) {
|
function highlightFilePaths(html) {
|
||||||
@@ -3192,7 +3240,7 @@
|
|||||||
termState.projectsDir = env.PROJECTS;
|
termState.projectsDir = env.PROJECTS;
|
||||||
termState.cwd = env.CWD || env.HOME;
|
termState.cwd = env.CWD || env.HOME;
|
||||||
updateCwdDisplay();
|
updateCwdDisplay();
|
||||||
termPrint('Z.AI Terminal v3.3.0', 'info');
|
termPrint('Z.AI Terminal v3.3.1', 'info');
|
||||||
termPrint('Home: ' + termState.homeDir, 'info');
|
termPrint('Home: ' + termState.homeDir, 'info');
|
||||||
termPrint('Type "help" for commands, "setup" for dev tools\n', 'info');
|
termPrint('Type "help" for commands, "setup" for dev tools\n', 'info');
|
||||||
}).catch(function() {});
|
}).catch(function() {});
|
||||||
@@ -3519,6 +3567,14 @@
|
|||||||
if (approvalState && approvalState.onApprove) approvalState.onApprove();
|
if (approvalState && approvalState.onApprove) approvalState.onApprove();
|
||||||
});
|
});
|
||||||
$('#approval-deny').addEventListener('click', closeApproval);
|
$('#approval-deny').addEventListener('click', closeApproval);
|
||||||
|
$('#html-preview-close').addEventListener('click', closeHtmlPreview);
|
||||||
|
$('#html-preview-newtab').addEventListener('click', function() {
|
||||||
|
var frame = $('#html-preview-frame');
|
||||||
|
if (!frame) return;
|
||||||
|
var doc = frame.contentDocument || frame.contentWindow.document;
|
||||||
|
var src = doc.documentElement.outerHTML;
|
||||||
|
openHtmlInNewTab('<!DOCTYPE html>' + src);
|
||||||
|
});
|
||||||
|
|
||||||
$('#theme-toggle-header').addEventListener('click', toggleTheme);
|
$('#theme-toggle-header').addEventListener('click', toggleTheme);
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user