Dashboard
Connect all your apps to a single dashboard
- ✓ README
- ✓ Files or snippet
- ✓ Security scan ran
- ✓ Checked — virus/secrets clean
- ✓ AI tool named
- — AI workflow note
- — Human contribution stated
- ✓ Original (no parent)
- ✓ Live preview
- ✓ Published in public record
Based on this build, not self-reported. Select a skill to find matching builders.
- ✓ Scan completed
- — No test files detected
- ✓ No known-vulnerable dependencies listed
- ✓ No secret-shaped hits in the scan report
- — Maintenance history: 0 stored versions, 1 platform event
These are precise checks on this object. BlaqVibes does not guarantee this app is secure.
Nova Workspace Dashboard — app-link scaffold
This project adds real, configurable launch destinations to the dashboard. It uses Node.js built-ins only; there are no npm dependencies.
Run locally
Requires Node.js 18 or later.
npm start
Open http://localhost:4173 (or the port shown in the server log). The dashboard calls the same-origin API and saves configured destinations to app-links.json.
Configure app destinations
- Open Applications → Manage links in the dashboard.
- Enter the URL for each app, e.g.
https://studio.your-company.com. - Save. The matching Open app button will launch that URL in a new tab.
- Clear a field and save to remove that destination.
The server accepts only http:// and https:// URLs, rejects embedded credentials, and writes the config atomically. You can also edit app-links.json directly. If you open the HTML without the included server, destinations are saved in that browser's local storage instead.
API
GET /api/health— basic server health response.GET /api/app-links— read the six configured destinations.PUT /api/app-links— replace the destinations with a JSON object keyed by app name.
Example:
curl -X PUT http://localhost:4173/api/app-links \
-H 'Content-Type: application/json' \
-d '{"Creative Studio":"https://studio.example.com","Analytics Hub":"https://analytics.example.com"}'
Missing app keys are saved as empty destinations. A hostname without a scheme is stored as HTTPS.
Important before deployment
The dashboard's KPI values, chart series, and service-health indicators are still illustrative sample data; this scaffold only makes the app launch links configurable. The included API has no authentication or authorization and is intended for local development. Before deploying it to a shared or public environment, add authentication, authorization, request-origin/CSRF protections, HTTPS, and suitable persistent storage for your environment.
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Master Dashboard - WebGL Liquid</title>
<style>
* {
margin: 0;
padding: 0;
box-sizing: border-box;
}
body {
font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif;
overflow-x: hidden;
background: #0a0a0a;
color: #fff;
}
#liquid-canvas {
position: fixed;
top: 0;
left: 0;
width: 100%;
height: 100%;
z-index: 0;
}
.dashboard {
position: relative;
z-index: 1;
padding: 20px;
max-width: 1400px;
margin: 0 auto;
}
header {
background: rgba(255, 255, 255, 0.05);
backdrop-filter: blur(20px);
border-radius: 20px;
padding: 30px;
margin-bottom: 30px;
border: 1px solid rgba(255, 255, 255, 0.1);
}
h1 {
font-size: 2.5em;
background: linear-gradient(45deg, #667eea 0%, #764ba2 100%);
-webkit-background-clip: text;
-webkit-text-fill-color: transparent;
margin-bottom: 10px;
}
.subtitle {
color: rgba(255, 255, 255, 0.6);
font-size: 1.1em;
}
.stats-grid {
display: grid;
grid-template-columns: repeat(auto-fit, minmax(250px, 1fr));
gap: 20px;
margin-bottom: 30px;
}
.stat-card {
background: rgba(255, 255, 255, 0.05);
backdrop-filter: blur(20px);
border-radius: 15px;
padding: 25px;
border: 1px solid rgba(255, 255, 255, 0.1);
transition: all 0.3s ease;
cursor: pointer;
}
.stat-card:hover {
transform: translateY(-5px);
background: rgba(255, 255, 255, 0.08);
box-shadow: 0 10px 40px rgba(102, 126, 234, 0.3);
}
.stat-icon {
width: 50px;
height: 50px;
border-radius: 12px;
display: flex;
align-items: center;
justify-content: center;
font-size: 24px;
margin-bottom: 15px;
}
.stat-value {
font-size: 2em;
font-weight: bold;
margin-bottom: 5px;
}
.stat-label {
color: rgba(255, 255, 255, 0.6);
font-size: 0.9em;
}
.apps-grid {
display: grid;
grid-template-columns: repeat(auto-fit, minmax(300px, 1fr));
gap: 25px;
margin-bottom: 30px;
}
.app-card {
background: rgba(255, 255, 255, 0.05);
backdrop-filter: blur(20px);
border-radius: 20px;
padding: 30px;
border: 1px solid rgba(255, 255, 255, 0.1);
transition: all 0.3s ease;
cursor: pointer;
}
.app-card:hover {
transform: translateY(-5px);
background: rgba(255, 255, 255, 0.08);
box-shadow: 0 15px 50px rgba(0, 0, 0, 0.4);
}
.app-header {
display: flex;
align-items: center;
margin-bottom: 20px;
}
.app-icon {
width: 60px;
height: 60px;
border-radius: 15px;
display: flex;
align-items: center;
justify-content: center;
font-size: 30px;
margin-right: 15px;
}
.app-info h3 {
font-size: 1.3em;
margin-bottom: 5px;
}
.app-status {
font-size: 0.85em;
padding: 4px 12px;
border-radius: 20px;
display: inline-block;
}
.status-active {
background: rgba(34, 197, 94, 0.2);
color: #4ade80;
}
.status-warning {
background: rgba(251, 191, 36, 0.2);
color: #fbbf24;
}
.app-metrics {
display: grid;
grid-template-columns: 1fr 1fr;
gap: 15px;
margin-top: 20px;
}
.metric {
background: rgba(255, 255, 255, 0.03);
padding: 15px;
border-radius: 10px;
}
.metric-value {
font-size: 1.5em;
font-weight: bold;
color: #667eea;
}
.metric-label {
font-size: 0.85em;
color: rgba(255, 255, 255, 0.5);
margin-top: 5px;
}
.progress-bar {
width: 100%;
height: 8px;
background: rgba(255, 255, 255, 0.1);
border-radius: 10px;
overflow: hidden;
margin-top: 15px;
}
.progress-fill {
height: 100%;
background: linear-gradient(90deg, #667eea 0%, #764ba2 100%);
border-radius: 10px;
transition: width 0.3s ease;
}
.btn {
background: linear-gradient(45deg, #667eea 0%, #764ba2 100%);
color: white;
border: none;
padding: 12px 25px;
border-radius: 10px;
font-size: 1em;
cursor: pointer;
margin-top: 15px;
transition: all 0.3s ease;
}
.btn:hover {
transform: scale(1.05);
box-shadow: 0 5px 20px rgba(102, 126, 234, 0.5);
}
</style>
</head>
<body>
<canvas id="liquid-canvas"></canvas>
<div class="dashboard">
<header>
<h1>Master Dashboard</h1>
<p class="subtitle">Real-time monitoring and analytics</p>
</header>
<div class="stats-grid">
<div class="stat-card">
<div class="stat-icon" style="background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);">
📊
</div>
<div class="stat-value">1,284</div>
<div class="stat-label">Total Users</div>
</div>
<div class="stat-card">
<div class="stat-icon" style="background: linear-gradient(135deg, #f093fb 0%, #f5576c 100%);">
🚀
</div>
<div class="stat-value">98.5%</div>
<div class="stat-label">Uptime</div>
</div>
<div class="stat-card">
<div class="stat-icon" style="background: linear-gradient(135deg, #4facfe 0%, #00f2fe 100%);">
💰
</div>
<div class="stat-value">$45.2K</div>
<div class="stat-label">Revenue</div>
</div>
<div class="stat-card">
<div class="stat-icon" style="background: linear-gradient(135deg, #43e97b 0%, #38f9d7 100%);">
⚡
</div>
<div class="stat-value">342</div>
<div class="stat-label">Active Sessions</div>
</div>
</div>
<div class="apps-grid">
<div class="app-card">
<div class="app-header">
<div class="app-icon" style="background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);">
🎨
</div>
<div class="app-info">
<h3>Creative Studio</h3>
<span class="app-status status-active">● Active</span>
</div>
</div>
<div class="app-metrics">
<div class="metric">
<div class="metric-value">2.4K</div>
<div class="metric-label">Projects</div>
</div>
<div class="metric">
<div class="metric-value">89%</div>
<div class="metric-label">Usage</div>
</div>
</div>
<div class="progress-bar">
<div class="progress-fill" style="width: 89%;"></div>
</div>
<button class="btn">Open App</button>
</div>
<div class="app-card">
<div class="app-header">
<div class="app-icon" style="background: linear-gradient(135deg, #f093fb 0%, #f5576c 100%);">
📈
</div>
<div class="app-info">
<h3>Analytics Hub</h3>
<span class="app-status status-active">● Active</span>
</div>
</div>
<div class="app-metrics">
<div class="metric">
<div class="metric-value">15.2K</div>
<div class="metric-label">Events</div>
</div>
<div class="metric">
<div class="metric-value">67%</div>
<div class="metric-label">Processing</div>
</div>
</div>
<div class="progress-bar">
<div class="progress-fill" style="width: 67%;"></div>
</div>
<button class="btn">Open App</button>
</div>
<div class="app-card">
<div class="app-header">
<div class="app-icon" style="background: linear-gradient(135deg, #4facfe 0%, #00f2fe 100%);">
💬
</div>
<div class="app-info">
<h3>Chat System</h3>
<span class="app-status status-warning">● Updating</span>
</div>
</div>
<div class="app-metrics">
<div class="metric">
<div class="metric-value">892</div>
<div class="metric-label">Messages</div>
</div>
<div class="metric">
<div class="metric-value">45</div>
<div class="metric-label">Online</div>
</div>
</div>
<div class="progress-bar">
<div class="progress-fill" style="width: 45%;"></div>
</div>
<button class="btn">Open App</button>
</div>
<div class="app-card">
<div class="app-header">
<div class="app-icon" style="background: linear-gradient(135deg, #43e97b 0%, #38f9d7 100%);">
🔒
</div>
<div class="app-info">
<h3>Security Center</h3>
<span class="app-status status-active">● Active</span>
</div>
</div>
<div class="app-metrics">
<div class="metric">
<div class="metric-value">0</div>
<div class="metric-label">Threats</div>
</div>
<div class="metric">
<div class="metric-value">100%</div>
<div class="metric-label">Secure</div>
</div>
</div>
<div class="progress-bar">
<div class="progress-fill" style="width: 100%;"></div>
</div>
<button class="btn">Open App</button>
</div>
<div class="app-card">
<div class="app-header">
<div class="app-icon" style="background: linear-gradient(135deg, #fa709a 0%, #fee140 100%);">
📁
</div>
<div class="app-info">
<h3>File Manager</h3>
<span class="app-status status-active">● Active</span>
</div>
</div>
<div class="app-metrics">
<div class="metric">
<div class="metric-value">45GB</div>
<div class="metric-label">Storage</div>
</div>
<div class="metric">
<div class="metric-value">1.2K</div>
<div class="metric-label">Files</div>
</div>
</div>
<div class="progress-bar">
<div class="progress-fill" style="width: 72%;"></div>
</div>
<button class="btn">Open App</button>
</div>
<div class="app-card">
<div class="app-header">
<div class="app-icon" style="background: linear-gradient(135deg, #30cfd0 0%, #330867 100%);">
⚙️
</div>
<div class="app-info">
<h3>Settings</h3>
<span class="app-status status-active">● Active</span>
</div>
</div>
<div class="app-metrics">
<div class="metric">
<div class="metric-value">12</div>
<div class="metric-label">Configs</div>
</div>
<div class="metric">
<div class="metric-value">8</div>
<div class="metric-label">Modules</div>
</div>
</div>
<div class="progress-bar">
<div class="progress-fill" style="width: 92%;"></div>
</div>
<button class="btn">Open App</button>
</div>
</div>
</div>
<script>
// WebGL Liquid Effect
const canvas = document.getElementById('liquid-canvas');
const gl = canvas.getContext('webgl') || canvas.getContext('experimental-webgl');
if (!gl) {
alert('WebGL not supported');
}
// Vertex shader
const vertexShaderSource = `
attribute vec2 a_position;
void main() {
gl_Position = vec4(a_position, 0.0, 1.0);
}
`;
// Fragment shader with liquid effect
const fragmentShaderSource = `
precision highp float;
uniform vec2 u_resolution;
uniform float u_time;
uniform vec2 u_mouse;
vec3 palette(float t) {
vec3 a = vec3(0.5, 0.5, 0.5);
vec3 b = vec3(0.5, 0.5, 0.5);
vec3 c = vec3(1.0, 1.0, 1.0);
vec3 d = vec3(0.263, 0.416, 0.557);
return a + b * cos(6.28318 * (c * t + d));
}
void main() {
vec2 uv = (gl_FragCoord.xy * 2.0 - u_resolution) / u_resolution.y;
vec2 uv0 = uv;
vec3 finalColor = vec3(0.0);
for (float i = 0.0; i < 4.0; i++) {
uv = fract(uv * 1.5) - 0.5;
float d = length(uv) * exp(-length(uv0));
vec3 col = palette(length(uv0) + i * 0.4 + u_time * 0.4);
d = sin(d * 8.0 + u_time) / 8.0;
d = abs(d);
d = pow(0.01 / d, 1.2);
finalColor += col * d;
}
// Add mouse interaction
vec2 mouseEffect = u_mouse / u_resolution;
float mouseDist = length(uv - mouseEffect);
finalColor += vec3(0.1, 0.05, 0.2) * (1.0 - smoothstep(0.0, 0.5, mouseDist));
gl_FragColor = vec4(finalColor * 0.3, 1.0);
}
`;
function createShader(gl, type, source) {
const shader = gl.createShader(type);
gl.shaderSource(shader, source);
gl.compileShader(shader);
if (!gl.getShaderParameter(shader, gl.COMPILE_STATUS)) {
console.error('Shader compile error:', gl.getShaderInfoLog(shader));
gl.deleteShader(shader);
return null;
}
return shader;
}
function createProgram(gl, vertexShader, fragmentShader) {
const program = gl.createProgram();
gl.attachShader(program, vertexShader);
gl.attachShader(program, fragmentShader);
gl.linkProgram(program);
if (!gl.getProgramParameter(program, gl.LINK_STATUS)) {
console.error('Program link error:', gl.getProgramInfoLog(program));
gl.deleteProgram(program);
return null;
}
return program;
}
const vertexShader = createShader(gl, gl.VERTEX_SHADER, vertexShaderSource);
const fragmentShader = createShader(gl, gl.FRAGMENT_SHADER, fragmentShaderSource);
const program = createProgram(gl, vertexShader, fragmentShader);
const positionAttributeLocation = gl.getAttribLocation(program, 'a_position');
const resolutionUniformLocation = gl.getUniformLocation(program, 'u_resolution');
const timeUniformLocation = gl.getUniformLocation(program, 'u_time');
const mouseUniformLocation = gl.getUniformLocation(program, 'u_mouse');
const positionBuffer = gl.createBuffer();
gl.bindBuffer(gl.ARRAY_BUFFER, positionBuffer);
const positions = [
-1, -1,
1, -1,
-1, 1,
-1, 1,
1, -1,
1, 1,
];
gl.bufferData(gl.ARRAY_BUFFER, new Float32Array(positions), gl.STATIC_DRAW);
let mouseX = 0;
let mouseY = 0;
document.addEventListener('mousemove', (e) => {
mouseX = e.clientX;
mouseY = canvas.height - e.clientY;
});
function resizeCanvas() {
canvas.width = window.innerWidth;
canvas.height = window.innerHeight;
gl.viewport(0, 0, canvas.width, canvas.height);
}
window.addEventListener('resize', resizeCanvas);
resizeCanvas();
function render(time) {
time *= 0.001; // Convert to seconds
gl.clearColor(0, 0, 0, 1);
gl.clear(gl.COLOR_BUFFER_BIT);
gl.useProgram(program);
gl.enableVertexAttribArray(positionAttributeLocation);
gl.bindBuffer(gl.ARRAY_BUFFER, positionBuffer);
gl.vertexAttribPointer(positionAttributeLocation, 2, gl.FLOAT, false, 0, 0);
gl.uniform2f(resolutionUniformLocation, canvas.width, canvas.height);
gl.uniform1f(timeUniformLocation, time);
gl.uniform2f(mouseUniformLocation, mouseX, mouseY);
gl.drawArrays(gl.TRIANGLES, 0, 6);
requestAnimationFrame(render);
}
requestAnimationFrame(render);
// Add interactive animations
document.querySelectorAll('.stat-card, .app-card').forEach(card => {
card.addEventListener('click', function() {
this.style.transform = 'scale(0.95)';
setTimeout(() => {
this.style.transform = '';
}, 100);
});
});
// Animate stats on load
window.addEventListener('load', () => {
document.querySelectorAll('.stat-value').forEach((stat, index) => {
stat.style.opacity = '0';
setTimeout(() => {
stat.style.transition = 'opacity 0.5s ease';
stat.style.opacity = '1';
}, index * 100);
});
});
</script>
</body>
</html>body{font-family:system-ui,sans-serif;background:#0b1020;color:#e5e7eb;display:grid;place-items:center;min-height:100vh}HOW TO ACCESS
- Read README
- Explore Files
- Check Evidence
- Remix or Download