openvibers/openvibe.chat Commits
Vibe's rail: Tasks (Actor), Computers & robots (Bot) and Work together beside Messages, Rooms and Global chat; its hover only where a pointer hovers (#172)
Changes
@@@ -48,7 +48,7 @@ body.oc-app-body { overflow: hidden; }.vb-rail-note { margin: 14px 10px; color: var(--oc-muted); font-size: .9rem; line-height: 1.45; }.vb-rail-more { border-top: 1px solid var(--oc-line); margin-top: 6px; padding-top: 6px; display: grid; gap: 1px; }.vb-rail-more a { display: flex; align-items: center; gap: 10px; padding: 8px 10px; border-radius: 10px; color: var(--oc-muted); text-decoration: none; font-size: .9rem; }--.vb-rail-more a:hover { background: var(--oc-panel-2); color: var(--oc-text); }++@media (hover: hover) { .vb-rail-more a:hover { background: var(--oc-panel-2); color: var(--oc-text); } }.vb-allow { margin: 6px 10px 2px; font-size: .78rem; color: var(--oc-muted); }/* ── The conversation ─────────────────────────────────────────────────────── */@@@ -51,6 +51,9 @@ const ICON = {messages: '<svg viewBox="0 0 24 24" aria-hidden="true"><path d="M4 5h16v11H8l-4 4Z"/></svg>',rooms: '<svg viewBox="0 0 24 24" aria-hidden="true"><path d="M8 11a3 3 0 1 0 0-6 3 3 0 0 0 0 6Zm8 0a3 3 0 1 0 0-6 3 3 0 0 0 0 6ZM2 20c0-3 3-5 6-5s6 2 6 5M14 15c3 0 8 1 8 5"/></svg>',globe: '<svg viewBox="0 0 24 24" aria-hidden="true"><circle cx="12" cy="12" r="9"/><path d="M3 12h18M12 3c3 3 3 15 0 18M12 3c-3 3-3 15 0 18"/></svg>',++ tasks: '<svg viewBox="0 0 24 24" aria-hidden="true"><path d="M9 6h11M9 12h11M9 18h11"/><path d="m3 6 1.5 1.5L7 5M3 12l1.5 1.5L7 11M3 18l1.5 1.5L7 17"/></svg>',++ computer: '<svg viewBox="0 0 24 24" aria-hidden="true"><rect x="3" y="4" width="18" height="12" rx="2"/><path d="M8 20h8M12 16v4"/></svg>',++ team: '<svg viewBox="0 0 24 24" aria-hidden="true"><rect x="3" y="4" width="18" height="14" rx="2"/><path d="M7 9h6M7 13h10"/></svg>',};/** The mark Vibe signs its answers with (the network's V, in the accent). */@@@ -71,6 +74,9 @@ function rail({ chats, current, signedIn, allowance }) {</div><nav class="vb-rail-list" aria-label="Chats with Vibe">${list}</nav><nav class="vb-rail-more" aria-label="More of OpenVibe.Chat">++<a href="https://openvibe.actor/tasks" title="Every task you gave an agent, one-off or recurring, with what it cost">${ICON.tasks}<span>Tasks</span></a>++<a href="https://openvibe.bot/machines" title="Your computers and robots: pair one, see its screen, set what agents may do on it">${ICON.computer}<span>Computers & robots</span></a>++<a href="/work" title="A room where your team and Vibe work together: a work queue, alerts and a shared screen">${ICON.team}<span>Work together</span></a><a href="/messages">${ICON.messages}<span>Messages</span></a><a href="/rooms">${ICON.rooms}<span>Rooms and servers</span></a><a href="/">${ICON.globe}<span>Global chat</span></a>@@@ -128,6 +128,10 @@ t('the app page: signed out it invites a sign-in, signed in it lists the chats aconst signed = await web('GET', '/vibe', ann);assert.ok(signed.text.includes('What can I help with, Ann?'));assert.ok(signed.text.includes('class="vb-chat" href="/vibe/v-'), 'the rail lists their chats');++ // The rail leads to the rest of the person's agent: their tasks, their computers and robots, team workspaces.++ assert.ok(/href="https:\/\/openvibe\.actor\/tasks"[^>]*>[\s\S]*?<span>Tasks<\/span>/.test(signed.text), 'Tasks');++ assert.ok(/href="https:\/\/openvibe\.bot\/machines"[^>]*>[\s\S]*?<span>Computers & robots<\/span>/.test(signed.text), 'Computers & robots');++ assert.ok(/href="\/work"[^>]*>[\s\S]*?<span>Work together<\/span>/.test(signed.text), 'Work together');const form = await web('POST', '/vibe', ann, { message: 'hello from a form' });assert.strictEqual(form.status, 303);assert.ok(/^\/vibe\/v-[0-9a-f]{12}$/.test(form.location), form.location);
@@ -48,7 +48,7 @@ body.oc-app-body { overflow: hidden; }
@@ -48,7 +48,7 @@ body.oc-app-body { overflow: hidden; }
.vb-rail-note { margin: 14px 10px; color: var(--oc-muted); font-size: .9rem; line-height: 1.45; }
.vb-rail-note { margin: 14px 10px; color: var(--oc-muted); font-size: .9rem; line-height: 1.45; }
.vb-rail-more { border-top: 1px solid var(--oc-line); margin-top: 6px; padding-top: 6px; display: grid; gap: 1px; }
.vb-rail-more { border-top: 1px solid var(--oc-line); margin-top: 6px; padding-top: 6px; display: grid; gap: 1px; }
.vb-rail-more a { display: flex; align-items: center; gap: 10px; padding: 8px 10px; border-radius: 10px; color: var(--oc-muted); text-decoration: none; font-size: .9rem; }
.vb-rail-more a { display: flex; align-items: center; gap: 10px; padding: 8px 10px; border-radius: 10px; color: var(--oc-muted); text-decoration: none; font-size: .9rem; }
-.vb-rail-more a:hover { background: var(--oc-panel-2); color: var(--oc-text); }
+@media (hover: hover) { .vb-rail-more a:hover { background: var(--oc-panel-2); color: var(--oc-text); } }
.vb-allow { margin: 6px 10px 2px; font-size: .78rem; color: var(--oc-muted); }
.vb-allow { margin: 6px 10px 2px; font-size: .78rem; color: var(--oc-muted); }
/* ── The conversation ─────────────────────────────────────────────────────── */
/* ── The conversation ─────────────────────────────────────────────────────── */
@@ -51,6 +51,9 @@ const ICON = {
@@ -51,6 +51,9 @@ const ICON = {
messages: '<svg viewBox="0 0 24 24" aria-hidden="true"><path d="M4 5h16v11H8l-4 4Z"/></svg>',
messages: '<svg viewBox="0 0 24 24" aria-hidden="true"><path d="M4 5h16v11H8l-4 4Z"/></svg>',
rooms: '<svg viewBox="0 0 24 24" aria-hidden="true"><path d="M8 11a3 3 0 1 0 0-6 3 3 0 0 0 0 6Zm8 0a3 3 0 1 0 0-6 3 3 0 0 0 0 6ZM2 20c0-3 3-5 6-5s6 2 6 5M14 15c3 0 8 1 8 5"/></svg>',
rooms: '<svg viewBox="0 0 24 24" aria-hidden="true"><path d="M8 11a3 3 0 1 0 0-6 3 3 0 0 0 0 6Zm8 0a3 3 0 1 0 0-6 3 3 0 0 0 0 6ZM2 20c0-3 3-5 6-5s6 2 6 5M14 15c3 0 8 1 8 5"/></svg>',
globe: '<svg viewBox="0 0 24 24" aria-hidden="true"><circle cx="12" cy="12" r="9"/><path d="M3 12h18M12 3c3 3 3 15 0 18M12 3c-3 3-3 15 0 18"/></svg>',
globe: '<svg viewBox="0 0 24 24" aria-hidden="true"><circle cx="12" cy="12" r="9"/><path d="M3 12h18M12 3c3 3 3 15 0 18M12 3c-3 3-3 15 0 18"/></svg>',
+ tasks: '<svg viewBox="0 0 24 24" aria-hidden="true"><path d="M9 6h11M9 12h11M9 18h11"/><path d="m3 6 1.5 1.5L7 5M3 12l1.5 1.5L7 11M3 18l1.5 1.5L7 17"/></svg>',
+ computer: '<svg viewBox="0 0 24 24" aria-hidden="true"><rect x="3" y="4" width="18" height="12" rx="2"/><path d="M8 20h8M12 16v4"/></svg>',
+ team: '<svg viewBox="0 0 24 24" aria-hidden="true"><rect x="3" y="4" width="18" height="14" rx="2"/><path d="M7 9h6M7 13h10"/></svg>',
};
};
/** The mark Vibe signs its answers with (the network's V, in the accent). */
/** The mark Vibe signs its answers with (the network's V, in the accent). */
@@ -71,6 +74,9 @@ function rail({ chats, current, signedIn, allowance }) {
@@ -71,6 +74,9 @@ function rail({ chats, current, signedIn, allowance }) {
</div>
</div>
<nav class="vb-rail-list" aria-label="Chats with Vibe">${list}</nav>
<nav class="vb-rail-list" aria-label="Chats with Vibe">${list}</nav>
<nav class="vb-rail-more" aria-label="More of OpenVibe.Chat">
<nav class="vb-rail-more" aria-label="More of OpenVibe.Chat">
+<a href="https://openvibe.actor/tasks" title="Every task you gave an agent, one-off or recurring, with what it cost">${ICON.tasks}<span>Tasks</span></a>
+<a href="https://openvibe.bot/machines" title="Your computers and robots: pair one, see its screen, set what agents may do on it">${ICON.computer}<span>Computers & robots</span></a>
+<a href="/work" title="A room where your team and Vibe work together: a work queue, alerts and a shared screen">${ICON.team}<span>Work together</span></a>
<a href="/messages">${ICON.messages}<span>Messages</span></a>
<a href="/messages">${ICON.messages}<span>Messages</span></a>
<a href="/rooms">${ICON.rooms}<span>Rooms and servers</span></a>
<a href="/rooms">${ICON.rooms}<span>Rooms and servers</span></a>
<a href="/">${ICON.globe}<span>Global chat</span></a>
<a href="/">${ICON.globe}<span>Global chat</span></a>
@@ -128,6 +128,10 @@ t('the app page: signed out it invites a sign-in, signed in it lists the chats a
@@ -128,6 +128,10 @@ t('the app page: signed out it invites a sign-in, signed in it lists the chats a
const signed = await web('GET', '/vibe', ann);
const signed = await web('GET', '/vibe', ann);
assert.ok(signed.text.includes('What can I help with, Ann?'));
assert.ok(signed.text.includes('What can I help with, Ann?'));
assert.ok(signed.text.includes('class="vb-chat" href="/vibe/v-'), 'the rail lists their chats');
assert.ok(signed.text.includes('class="vb-chat" href="/vibe/v-'), 'the rail lists their chats');
+ // The rail leads to the rest of the person's agent: their tasks, their computers and robots, team workspaces.
+ assert.ok(/href="https:\/\/openvibe\.actor\/tasks"[^>]*>[\s\S]*?<span>Tasks<\/span>/.test(signed.text), 'Tasks');
+ assert.ok(/href="https:\/\/openvibe\.bot\/machines"[^>]*>[\s\S]*?<span>Computers & robots<\/span>/.test(signed.text), 'Computers & robots');
+ assert.ok(/href="\/work"[^>]*>[\s\S]*?<span>Work together<\/span>/.test(signed.text), 'Work together');
const form = await web('POST', '/vibe', ann, { message: 'hello from a form' });
const form = await web('POST', '/vibe', ann, { message: 'hello from a form' });
assert.strictEqual(form.status, 303);
assert.strictEqual(form.status, 303);
assert.ok(/^\/vibe\/v-[0-9a-f]{12}$/.test(form.location), form.location);
assert.ok(/^\/vibe\/v-[0-9a-f]{12}$/.test(form.location), form.location);