Build a virtual desktop with shortcuts, a custom home folder, and a library of apps — all integrated into the File Manager using shortcuts, custom viewers, and the input:// filesystem.
<iframe id="tp-demo" src="/online/webapp/file-manager" width="100%" height="700" frameborder="0" style="border:1px solid #ccc; border-radius:4px;"></iframe>
<script>window._wsConnect('tp-demo', 'tpSocket');
window._tpSeq = function (cmds, done) {
var s = window._ws('tpSocket');
if (!s) return;
var i = 0;
var next = function () {
if (i >= cmds.length) { if (done) done(); return; }
var cmd = cmds[i++];
var args = cmd.concat([function () { setTimeout(next, 5); }]);
s.fire.apply(s, ['webapp::instance::request'].concat(args));
};
next();};
window._tpAppCode = function (renderFnStr) {
return 'module.exports = function () {\n' +
'var app = new ApplicationPrototype();\n' +
'var node = document.createElement("div");\n' +
'var win = null;\n' +
'var ready = new Application.Promise();\n' +
'app.bind("node", function () { return node; }, "");\n' +
'app.bind("window", function () { return win; }, "");\n' +
'app.bind("ready", function () { return ready; });\n' +
'app.bind("handleWindow", function (w) {\n' +
' win = w;\n' +
' w.emit("api-request::attached", []);\n' +
' w.on("api-request::ready", function (cb) { cb(ready); });\n' +
'});\n' +
'app.bind("render", function (cb) {\n' +
' (' + renderFnStr + ')(app, win, node, cb);\n' +
'});\n' +
'app.bind("destroy", function () {});\n' +
'app.bind("init", function () {\n' +
' app.render(function (err) {\n' +
' if (err) return ready.reject(err);\n' +
' ready.resolve(app);\n' +
' });\n' +
' return app;\n' +
'});\n' +
'return app;\n' +
'};';};
window._tpSetup = function () {
// --- CSV Table Viewer ---
var csvViewerCode = window._tpAppCode((function (app, win, node, cb) {
win.title('CSV Table'); win.icon('breeze/icons/mimetypes/64/text-csv');
win.height(450); win.width(700); win.scrolling(true);
var args = app.window().env().args || [];
if (!args[0]) { cb(); return; }
node.innerHTML = 'Parsing CSV...
';
Application.require('/files/api/modules/fs.js').then(function (fsModule) {
fsModule().read(args[0], null, true).response('text').then(function (text) {
var rows = text.trim().split('\n').map(function (r) { return r.split(',').map(function (c) { return c.trim(); }); });
var html = '';
rows.forEach(function (row, i) {
html += '';
row.forEach(function (cell) {
var tag = i === 0 ? 'th' : 'td';
var style = i === 0
? 'background:#4a6cf7;color:#fff;padding:8px 12px;text-align:left;font-weight:600;position:sticky;top:0'
: 'padding:6px 12px;border-bottom:1px solid #eee;background:' + (i % 2 ? '#f8f9fa' : '#fff');
html += '<' + tag + ' style="' + style + '">' + cell.replace(/';
});
html += ' ';
});
html += '
';
node.innerHTML = html;
});
});
cb();
}).toString());// --- Log Viewer (color-coded) ---
var logViewerCode = window._tpAppCode((function (app, win, node, cb) {
win.title('Log Viewer'); win.icon('breeze/icons/apps/48/utilities-log-viewer');
win.height(450); win.width(700); win.scrolling(true);
var args = app.window().env().args || [];
if (!args[0]) { cb(); return; }
node.innerHTML = 'Loading logs...
';
Application.require('/files/api/modules/fs.js').then(function (fsModule) {
fsModule().read(args[0], null, true).response('text').then(function (text) {
var lines = text.split('\n').map(function (line) {
var color = '#ccc';
if (line.match(/\b(error|fatal|fail)\b/i)) color = '#e74c3c';
else if (line.match(/\b(warn|warning)\b/i)) color = '#f39c12';
else if (line.match(/\b(info)\b/i)) color = '#3498db';
else if (line.match(/\b(debug)\b/i)) color = '#888';
else if (line.match(/\b(success|ok|done)\b/i)) color = '#27ae60';
return '' + line.replace(/';
}).join('');
node.innerHTML = '' + lines + '';
});
});
cb();
}).toString());// --- HTML Preview (renders HTML in iframe sandbox) ---
var htmlPreviewCode = window._tpAppCode((function (app, win, node, cb) {
win.title('HTML Preview'); win.icon('paper/icons/apps/internet-web-browser');
win.height(500); win.width(700);
var args = app.window().env().args || [];
if (!args[0]) { cb(); return; }
node.innerHTML = 'Loading...
';
Application.require('/files/api/modules/fs.js').then(function (fsModule) {
fsModule().read(args[0], null, true).response('text').then(function (text) {
var iframe = document.createElement('iframe');
iframe.style.cssText = 'width:100%;height:100%;border:none';
iframe.sandbox = 'allow-scripts';
node.innerHTML = '';
node.appendChild(iframe);
iframe.srcdoc = text;
});
});
cb();
}).toString());
// --- Hex Viewer ---
var hexViewerCode = window._tpAppCode((function (app, win, node, cb) {
win.title('Hex Viewer'); win.icon('breeze/icons/apps/48/okteta');
win.height(450); win.width(700); win.scrolling(true);
var args = app.window().env().args || [];
if (!args[0]) { cb(); return; }
node.innerHTML = 'Reading bytes...
';
Application.require('/files/api/modules/fs.js').then(function (fsModule) {
fsModule().read(args[0], function (err, data) {
if (err || !data) { node.innerHTML = 'Error reading file
'; return; }
var bytes = new Uint8Array(data);
var html = '';
for (var i = 0; i < Math.min(bytes.length, 4096); i += 16) {
var offset = ('0000000' + i.toString(16)).slice(-8);
var hexPart = '';
var ascPart = '';
for (var j = 0; j < 16; j++) {
if (i + j < bytes.length) {
var b = bytes[i + j];
hexPart += ('0' + b.toString(16)).slice(-2) + ' ';
ascPart += (b >= 32 && b < 127) ? String.fromCharCode(b) : '.';
} else {
hexPart += ' ';
ascPart += ' ';
}
if (j === 7) hexPart += ' ';
}
html += '' + offset + ' ' + hexPart + ' ' + ascPart.replace(/';
}
if (bytes.length > 4096) html += '... showing first 4096 of ' + bytes.length + ' bytes';
html += '';
node.innerHTML = html;
});
});
cb();
}).toString());
// --- Color palette viewer for .colors files ---
var colorViewerCode = window._tpAppCode((function (app, win, node, cb) {
win.title('Color Palette'); win.icon('paper/small/apps/preferences-color-symbolic');
win.height(350); win.width(450);
var args = app.window().env().args || [];
if (!args[0]) { cb(); return; }
Application.require('/files/api/modules/fs.js').then(function (fsModule) {
fsModule().read(args[0], null, true).response('text').then(function (text) {
var colors = text.split('\n').map(function (l) { return l.trim(); }).filter(function (l) { return l && l.charAt(0) !== '#'; });
var html = '';
html += 'Color Palette (' + colors.length + ' colors)
';
html += '';
colors.forEach(function (c) {
var parts = c.split(/\s+/);
var color = parts[0];
var name = parts.slice(1).join(' ') || color;
html += '';
html += '';
html += '' + name + '';
html += '' + color + '';
html += '';
});
html += '';
node.innerHTML = html;
});
});
cb();
}).toString());
// --- Sample data files ---
var csvData = 'Name,Email,Role,Status\nAlice Smith,alice@example.com,Engineer,Active\nBob Jones,bob@example.com,Designer,Active\nCharlie Brown,charlie@example.com,Manager,On Leave\nDiana Prince,diana@example.com,Engineer,Active\nEve Wilson,eve@example.com,QA,Active\nFrank Miller,frank@example.com,DevOps,Active';
var logData = [
'2026-04-03 08:00:01 [INFO] Server starting on port 3000',
'2026-04-03 08:00:02 [INFO] Database connected successfully',
'2026-04-03 08:00:03 [DEBUG] Loading middleware: cors, compression, auth',
'2026-04-03 08:01:15 [INFO] Request: GET /api/users (200) 45ms',
'2026-04-03 08:02:30 [WARNING] Rate limit approaching for IP 192.168.1.50',
'2026-04-03 08:03:45 [INFO] Request: POST /api/orders (201) 120ms',
'2026-04-03 08:05:00 [ERROR] Failed to send email: SMTP connection timeout',
'2026-04-03 08:05:01 [INFO] Retry email send in 30s',
'2026-04-03 08:05:31 [SUCCESS] Email sent successfully to user@example.com',
'2026-04-03 08:10:00 [WARNING] Memory usage at 85%',
'2026-04-03 08:15:22 [ERROR] Unhandled promise rejection in /api/export',
'2026-04-03 08:15:23 [FATAL] Process crashed — restarting...',
'2026-04-03 08:15:25 [INFO] Server restarted successfully',
'2026-04-03 08:20:00 [DEBUG] Garbage collection completed: freed 128MB'
].join('\n');
var htmlPage = '\n\n\n\n\n\nInteractive Page
\n\n Counter Demo
\n Count: 0
\n \n\n\n Form Demo
\n \n\n\n';
var colorsData = '# Brand Colors\n#4a6cf7 Primary Blue\n#6a3cf7 Purple Accent\n#27ae60 Success Green\n#e74c3c Error Red\n#f39c12 Warning Orange\n#3498db Info Blue\n\n# Neutral\n#1a1a2e Dark Navy\n#333333 Text Dark\n#666666 Text Medium\n#999999 Text Light\n#f8f9fa Background';
window._tpSeq([
['gui:specialPaths:clear'],
['fs:mkdirp', 'input://apps/'],
['fs:mkdirp', 'input://desktop/'],
['fs:mkdirp', 'input://desktop/Documents/'],
['fs:mkdirp', 'input://desktop/Data/'],
['fs:mkdirp', 'input://desktop/Logs/'],
['fs:mkdirp', 'input://desktop/Web/'],
['fs:mkdirp', 'input://desktop/Design/'],
// Write app modules
['fs:write', 'input://apps/csv-viewer.js', csvViewerCode],
['fs:write', 'input://apps/log-viewer.js', logViewerCode],
['fs:write', 'input://apps/html-preview.js', htmlPreviewCode],
['fs:write', 'input://apps/hex-viewer.js', hexViewerCode],
['fs:write', 'input://apps/color-viewer.js', colorViewerCode],
// Write data files
['fs:write', 'input://desktop/Data/team-roster.csv', csvData],
['fs:write', 'input://desktop/Logs/server.log', logData],
['fs:write', 'input://desktop/Web/interactive-page.html', htmlPage],
['fs:write', 'input://desktop/Design/brand.colors', colorsData],
['fs:write', 'input://desktop/Documents/notes.txt', 'Meeting notes - April 2026\n\n- Discussed Q2 roadmap\n- Archive viewer shipped\n- Custom apps API released\n- Next: real-time collaboration'],
['fs:write', 'input://desktop/Documents/data.json', JSON.stringify({project:"webapp-desktop",version:"1.0",features:["csv-viewer","log-viewer","html-preview","hex-viewer","color-palette","shortcuts"],status:"demo"}, null, 2)],
// Create shortcut files
['fs:createShortcut', 'input://desktop/Open Photo Editor.lnk', { app: 'photo-editor', args: [], name: 'Photo Editor', icon: 'paper/*/multimedia-photo-viewer.png' }],
['fs:createShortcut', 'input://desktop/Open Code Editor.lnk', { app: 'code-editor', args: [], name: 'Code Editor', icon: 'breeze*book-edit' }],
// Register all custom apps
['apps:register', {
'csv-viewer': { path: 'input://apps/csv-viewer.js', name: 'CSV Table Viewer', icon: 'breeze/icons/mimetypes/64/text-csv', comment: 'View CSV as styled table', mimetypes: ['text/csv'], 'file-handlers': ['\\.csv
sgapps.io