Loading...
Loading...
Create or update a Hubble HTML App: a folder-local .html file Hubble runs as a self-contained interactive UI, with Alpine, Tailwind, Hubble theme tokens, and the injected hubble runtime API.
npx skill4agent add bholmesdev/hubble-skills create-html-app.html.htmlcreate-embedhubbleAlpine<script>node_modulesallow-scriptsallow-forms@submit.preventallow-same-originallow-top-navigationallow-popupsallow-popups-to-escape-sandboxallow-downloadsallow-modalshubble.filesawait hubble.files.list("todos/*.md")
// → [{ name, path, modified_at, size }], sorted by path
await hubble.files.read("notes/today.md")
// → { path, body, properties }
await hubble.files.open("notes/today.md")
// → { path }, navigates the editor to the file
await hubble.files.create({ path, body, properties, open })
// → { path, body, properties }
await hubble.files.update(path, { body, properties })
// → { path, body, properties }, patch
await hubble.files.remove("notes/today.md")
// → { path }safe*<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1" />
<title>Folder files</title>
</head>
<body class="m-0 bg-background p-3 font-sans text-foreground">
<main
class="grid gap-3 rounded-md border border-border bg-card p-3 text-card-foreground"
x-data="{
files: [],
error: '',
async init() {
try {
this.files = await hubble.files.list('**/*.md')
} catch (error) {
this.error = error.message || 'Could not load files'
}
},
}"
>
<header class="flex items-center justify-between gap-3">
<h1 class="m-0 text-base font-semibold">Folder files</h1>
<span class="text-sm text-muted-foreground" x-text="`${files.length} files`"></span>
</header>
<p class="m-0 text-sm text-muted-foreground" x-show="!error && files.length === 0">
Loading files...
</p>
<p class="m-0 text-sm text-destructive" x-show="error" x-text="error"></p>
<ul class="m-0 grid list-none gap-2 p-0" x-show="!error && files.length > 0">
<template x-for="file in files" :key="file.path">
<li class="rounded-sm border border-border bg-background px-3 py-2">
<span class="text-sm font-medium" x-text="file.path"></span>
</li>
</template>
</ul>
</main>
</body>
</html>x-dataAlpine.data()<script><script>
document.addEventListener('alpine:init', () => {
Alpine.data('fileList', () => ({
files: [],
error: '',
async init() {
try {
this.files = await hubble.files.list('**/*.md')
} catch (error) {
this.error = error.message || 'Could not load files'
}
},
}))
})
</script>
<main x-data="fileList">…</main>x-data<>&alpine:initbg-backgroundbg-cardbg-popovertext-foregroundtext-muted-foregroundtext-card-foregroundborder-borderborder-inputring-ringfocus-visible:ring-ringbg-primary text-primary-foregroundbg-secondary text-secondary-foregroundhover:bg-accentbg-selected text-selected-foregroundgap-2gap-3p-2p-3px-3py-2rounded-smrounded-md