Wire UI dock to crimata-dock service

- Fetch installed apps from /dock/apps on init instead of hardcoded list
- Refresh running status every 10s
- Map dock response to app format (add url: /apps/{id})
- Show running indicator dot on active apps in dock

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
Andrew Gundersen 2026-02-27 11:13:37 -05:00
commit ac3215abf5
3 changed files with 33 additions and 7 deletions

View file

@ -57,6 +57,7 @@
<template x-for="app in installedApps" :key="app.id">
<div class="dock-icon" @click="openApp(app)" :title="app.name">
<span x-text="app.icon"></span>
<span class="dock-dot" x-show="app.running"></span>
</div>
</template>
</div>

View file

@ -122,15 +122,28 @@ document.addEventListener('alpine:init', () => {
},
// ── Installed apps ────────────────────────────────────────────────────
// Loaded from crimata.json manifests on the server
installedApps: [
{ id: 'bio', name: 'Bio', icon: '🪪', url: '/apps/bio' },
{ id: 'contacts', name: 'Contacts', icon: '👥', url: '/apps/contacts' },
{ id: 'blog', name: 'Blog', icon: '📝', url: '/apps/blog' },
],
installedApps: [],
async loadApps() {
try {
const res = await fetch('/dock/apps')
const data = await res.json()
this.installedApps = data.map(app => ({
...app,
url: `/apps/${app.id}`,
}))
} catch (e) {
console.error('dock unreachable:', e)
}
},
// ── Init ──────────────────────────────────────────────────────────────
init() {
async init() {
await this.loadApps()
// Refresh running status every 10s
setInterval(() => this.loadApps(), 10_000)
// Open bio full-screen on load
const bio = this.installedApps.find(a => a.id === 'bio')
if (bio) this.openApp(bio)

View file

@ -15,6 +15,7 @@
}
.dock-icon {
position: relative;
width: 52px;
height: 52px;
border-radius: 12px;
@ -28,6 +29,17 @@
user-select: none;
}
.dock-dot {
position: absolute;
bottom: -6px;
left: 50%;
transform: translateX(-50%);
width: 4px;
height: 4px;
border-radius: 50%;
background: rgba(255,255,255,0.9);
}
.dock-icon:hover {
transform: translateY(-8px) scale(1.1);
background: rgba(255,255,255,0.35);