openvibers/openvibe.cam Commits
Home: the scenes are labelled Example and carry no written-in viewer (#88)
Changes
@@@ -33,33 +33,34 @@ function frameUrl(config, camera) {return `${String(config.upstreams.media).replace(/\/+$/, '')}/live/${encodeURIComponent(camera.slot)}/frame.jpg?w=640`;}--// The home's three scenes show the real thing (the owner, 10-31: placeholder pictures made rooms look unfinished). They--// share one picture, public/img/cam-sample.svg, drawn so it shows no one.++// The home's three scenes show what the product does on one sample picture, public/img/cam-sample.svg, drawn so it shows++// no one. The camera list and grants are the signed-in owner's, private and not in this public page, so the scenes are++// illustrations and each says Example — never a written-in viewer, camera name or count.const SAMPLE = '/img/cam-sample.svg';const CAMERA = '<svg viewBox="0 0 24 24" aria-hidden="true" focusable="false"><path d="M4 8h3l2-3h6l2 3h3v11H4z" fill="none" stroke="currentColor" stroke-width="2" stroke-linejoin="round"/><circle cx="12" cy="13" r="3.5" fill="none" stroke="currentColor" stroke-width="2"/></svg>';const LOCK = '<svg viewBox="0 0 24 24" aria-hidden="true" focusable="false"><rect x="5" y="11" width="14" height="10" rx="2" fill="none" stroke="currentColor" stroke-width="2"/><path d="M8 11V8a4 4 0 0 1 8 0v3" fill="none" stroke="currentColor" stroke-width="2"/></svg>';/** The cam button on a live stream: the frame, the shutter's flash, and the line it posts in the chat. */function liveStillDemo() {-- return `<figure class="cm-demo-live" role="img" aria-label="A live stream, the cam button's flash, and the chat line it posts">--<div class="cm-live-frame"><img src="${SAMPLE}" alt="" width="320" height="240" loading="lazy"><span class="cm-live-badge">Live</span><span class="cm-live-flash"></span><span class="cm-live-btn">${CAMERA}</span></div>--<p class="cm-live-chat"><span class="cm-live-who">ada</span> caught a still: <q>the sun just touched the ridge</q></p>++ return `<figure class="cm-demo-live" role="img" aria-label="Example: a live stream, the cam button's flash, and the chat line it posts">++<div class="cm-live-frame"><img src="${SAMPLE}" alt="" width="320" height="240" loading="lazy"><span class="cm-live-badge">Live · example</span><span class="cm-live-flash"></span><span class="cm-live-btn">${CAMERA}</span></div>++<p class="cm-live-chat"><span class="cm-live-who">Chat</span> a still is posted to the stream</p></figure>`;}/** A paired camera and the one grant on it: who, for how long, and the way to take it back. */function grantDemo() {-- return `<div class="cm-demo-grant" role="img" aria-label="A private camera shared with one person for a week">--<div class="cm-g-cam"><img src="${SAMPLE}" alt="" width="64" height="48" loading="lazy"><span class="cm-g-name"><b>Back garden</b><span>Raspberry Pi · private</span></span><span class="cm-g-lock">${LOCK}</span></div>--<div class="cm-g-grant"><span class="cm-g-who">@ada can watch</span><span class="cm-g-left">5 of 7 days left</span><span class="cm-g-bar"><i></i></span><span class="cm-g-revoke">Revoke</span></div>++ return `<div class="cm-demo-grant" role="img" aria-label="Example: a private camera shared with one viewer for a week">++<div class="cm-g-cam"><img src="${SAMPLE}" alt="" width="64" height="48" loading="lazy"><span class="cm-g-name"><b>A private camera</b><span>Example grant · Raspberry Pi</span></span><span class="cm-g-lock">${LOCK}</span></div>++<div class="cm-g-grant"><span class="cm-g-who">One viewer</span><span class="cm-g-left">for a week</span><span class="cm-g-bar"><i></i></span><span class="cm-g-revoke">Revoke</span></div></div>`;}/** One picture through every filter the camera app has (the same CSS as public/js/cam.js), Warm picked. */function filtersDemo() {const thumbs = Object.entries(FILTER_LABEL).map(([id, label]) => `<li${id === 'warm' ? ' class="is-on"' : ''}><img class="cm-f-${id}" src="${SAMPLE}" alt="" width="64" height="48" loading="lazy"><span>${esc(label)}</span></li>`).join('');-- return `<figure class="cm-demo-filters" role="img" aria-label="One picture in each of the camera's filters, with Warm picked and saved to Pics">--<div class="cm-f-main"><img class="cm-f-warm" src="${SAMPLE}" alt="" width="320" height="240" loading="lazy"><span class="cm-f-saved">Warm · saved to Pics</span></div>++ return `<figure class="cm-demo-filters" role="img" aria-label="Example: one picture in each of the camera's filters, with Warm picked and saved to Pics">++<div class="cm-f-main"><img class="cm-f-warm" src="${SAMPLE}" alt="" width="320" height="240" loading="lazy"><span class="cm-f-saved">Example · Warm · saved to Pics</span></div><ul class="cm-f-strip">${thumbs}</ul></figure>`;}nnew file mode 100644@@@ -0,0 +1,18 @@++'use strict';++// Cam's home scenes are illustrations on the sample picture: the camera list and grants are private to their owner, so++// the public page must label them Example and never print a written-in viewer, camera name or count.++const assert = require('assert');++const views = require('../server/views');++++const page = views.home({});++assert.ok(page.includes('Live · example'), 'the live frame says Example');++assert.ok(page.includes('Example grant'), 'the grant says Example');++assert.ok(page.includes('Example · Warm · saved to Pics'), 'the filter strip says Example');++assert.ok(page.includes('a still is posted to the stream'), 'the chat line describes the action, not a person');++assert.ok(!/@ada|\bada\b|Back garden|5 of 7 days|sun just touched the ridge/.test(page), 'no written-in viewer, camera name or count');++++// The signed-in flag only changes the link in the privacy rules; it must not put any camera or grant on the public page.++const signedIn = views.home({ signedIn: true });++assert.ok(signedIn.includes('href="/my"'), 'a signed-in owner gets the way to their cameras');++assert.ok(!/Back garden|@ada|5 of 7 days/.test(signedIn), 'and still no private camera or grant is drawn');++console.log('cam home: every scene is labelled Example and no written-in person, camera or count remains');@@@ -1,7 +1,7 @@'use strict';--// Cam's home shows the real thing (the owner, 10-31: placeholder pictures made the rooms look unfinished): a live frame--// with the cam button's flash and the chat line it posts, a camera's one grant, and one picture through every filter the--// camera app has, with the same CSS as the app, so the home can never show a filter the camera does not apply.++// Cam's home shows the product on its sample picture, labelled Example: a live frame with the cam button's flash and the++// chat line it posts, a camera's one grant, and one picture through every filter the camera app has, with the same CSS as++// the app, so the home can never show a filter the camera does not apply.const assert = require('assert');const fs = require('fs');const path = require('path');@@@ -21,10 +21,10 @@ for (const [id, filter] of Object.entries(app)) {}const home = views.home({ signedIn: false });--assert.ok(home.includes('class="cm-demo-live"') && home.includes('class="cm-live-flash"') && home.includes('caught a still'), 'a live still, shown');--assert.ok(home.includes('class="cm-demo-grant"') && home.includes('can watch') && home.includes('Revoke'), 'a grant, shown');++assert.ok(home.includes('class="cm-demo-live"') && home.includes('class="cm-live-flash"') && home.includes('a still is posted to the stream'), 'a live still, shown as an example');++assert.ok(home.includes('class="cm-demo-grant"') && home.includes('One viewer') && home.includes('Revoke'), 'a grant, shown as an example');assert.ok(home.includes('class="cm-demo-filters"'), 'the filters, shown');for (const id of Object.keys(app)) assert.ok(home.includes(`class="cm-f-${id}"`), `the ${id} filter is in the strip`);assert.ok(!/<img src="\/img\/cam-shutter\.svg"/.test(home), 'no placeholder picture in a scene');assert.ok(!/<script/i.test(sample) && !/href=|xlink:/i.test(sample), 'the sample picture is a plain drawing');--console.log(`cam home scenes: ${Object.keys(app).length} filters equal to the camera's, three real scenes`);++console.log(`cam home scenes: ${Object.keys(app).length} filters equal to the camera's, three example scenes`);
@@ -33,33 +33,34 @@ function frameUrl(config, camera) {
@@ -33,33 +33,34 @@ function frameUrl(config, camera) {
return `${String(config.upstreams.media).replace(/\/+$/, '')}/live/${encodeURIComponent(camera.slot)}/frame.jpg?w=640`;
return `${String(config.upstreams.media).replace(/\/+$/, '')}/live/${encodeURIComponent(camera.slot)}/frame.jpg?w=640`;
}
}
-// The home's three scenes show the real thing (the owner, 10-31: placeholder pictures made rooms look unfinished). They
-// share one picture, public/img/cam-sample.svg, drawn so it shows no one.
+// The home's three scenes show what the product does on one sample picture, public/img/cam-sample.svg, drawn so it shows
+// no one. The camera list and grants are the signed-in owner's, private and not in this public page, so the scenes are
+// illustrations and each says Example — never a written-in viewer, camera name or count.
const SAMPLE = '/img/cam-sample.svg';
const SAMPLE = '/img/cam-sample.svg';
const CAMERA = '<svg viewBox="0 0 24 24" aria-hidden="true" focusable="false"><path d="M4 8h3l2-3h6l2 3h3v11H4z" fill="none" stroke="currentColor" stroke-width="2" stroke-linejoin="round"/><circle cx="12" cy="13" r="3.5" fill="none" stroke="currentColor" stroke-width="2"/></svg>';
const CAMERA = '<svg viewBox="0 0 24 24" aria-hidden="true" focusable="false"><path d="M4 8h3l2-3h6l2 3h3v11H4z" fill="none" stroke="currentColor" stroke-width="2" stroke-linejoin="round"/><circle cx="12" cy="13" r="3.5" fill="none" stroke="currentColor" stroke-width="2"/></svg>';
const LOCK = '<svg viewBox="0 0 24 24" aria-hidden="true" focusable="false"><rect x="5" y="11" width="14" height="10" rx="2" fill="none" stroke="currentColor" stroke-width="2"/><path d="M8 11V8a4 4 0 0 1 8 0v3" fill="none" stroke="currentColor" stroke-width="2"/></svg>';
const LOCK = '<svg viewBox="0 0 24 24" aria-hidden="true" focusable="false"><rect x="5" y="11" width="14" height="10" rx="2" fill="none" stroke="currentColor" stroke-width="2"/><path d="M8 11V8a4 4 0 0 1 8 0v3" fill="none" stroke="currentColor" stroke-width="2"/></svg>';
/** The cam button on a live stream: the frame, the shutter's flash, and the line it posts in the chat. */
/** The cam button on a live stream: the frame, the shutter's flash, and the line it posts in the chat. */
function liveStillDemo() {
function liveStillDemo() {
- return `<figure class="cm-demo-live" role="img" aria-label="A live stream, the cam button's flash, and the chat line it posts">
-<div class="cm-live-frame"><img src="${SAMPLE}" alt="" width="320" height="240" loading="lazy"><span class="cm-live-badge">Live</span><span class="cm-live-flash"></span><span class="cm-live-btn">${CAMERA}</span></div>
-<p class="cm-live-chat"><span class="cm-live-who">ada</span> caught a still: <q>the sun just touched the ridge</q></p>
+ return `<figure class="cm-demo-live" role="img" aria-label="Example: a live stream, the cam button's flash, and the chat line it posts">
+<div class="cm-live-frame"><img src="${SAMPLE}" alt="" width="320" height="240" loading="lazy"><span class="cm-live-badge">Live · example</span><span class="cm-live-flash"></span><span class="cm-live-btn">${CAMERA}</span></div>
+<p class="cm-live-chat"><span class="cm-live-who">Chat</span> a still is posted to the stream</p>
</figure>`;
</figure>`;
}
}
/** A paired camera and the one grant on it: who, for how long, and the way to take it back. */
/** A paired camera and the one grant on it: who, for how long, and the way to take it back. */
function grantDemo() {
function grantDemo() {
- return `<div class="cm-demo-grant" role="img" aria-label="A private camera shared with one person for a week">
-<div class="cm-g-cam"><img src="${SAMPLE}" alt="" width="64" height="48" loading="lazy"><span class="cm-g-name"><b>Back garden</b><span>Raspberry Pi · private</span></span><span class="cm-g-lock">${LOCK}</span></div>
-<div class="cm-g-grant"><span class="cm-g-who">@ada can watch</span><span class="cm-g-left">5 of 7 days left</span><span class="cm-g-bar"><i></i></span><span class="cm-g-revoke">Revoke</span></div>
+ return `<div class="cm-demo-grant" role="img" aria-label="Example: a private camera shared with one viewer for a week">
+<div class="cm-g-cam"><img src="${SAMPLE}" alt="" width="64" height="48" loading="lazy"><span class="cm-g-name"><b>A private camera</b><span>Example grant · Raspberry Pi</span></span><span class="cm-g-lock">${LOCK}</span></div>
+<div class="cm-g-grant"><span class="cm-g-who">One viewer</span><span class="cm-g-left">for a week</span><span class="cm-g-bar"><i></i></span><span class="cm-g-revoke">Revoke</span></div>
</div>`;
</div>`;
}
}
/** One picture through every filter the camera app has (the same CSS as public/js/cam.js), Warm picked. */
/** One picture through every filter the camera app has (the same CSS as public/js/cam.js), Warm picked. */
function filtersDemo() {
function filtersDemo() {
const thumbs = Object.entries(FILTER_LABEL).map(([id, label]) => `<li${id === 'warm' ? ' class="is-on"' : ''}><img class="cm-f-${id}" src="${SAMPLE}" alt="" width="64" height="48" loading="lazy"><span>${esc(label)}</span></li>`).join('');
const thumbs = Object.entries(FILTER_LABEL).map(([id, label]) => `<li${id === 'warm' ? ' class="is-on"' : ''}><img class="cm-f-${id}" src="${SAMPLE}" alt="" width="64" height="48" loading="lazy"><span>${esc(label)}</span></li>`).join('');
- return `<figure class="cm-demo-filters" role="img" aria-label="One picture in each of the camera's filters, with Warm picked and saved to Pics">
-<div class="cm-f-main"><img class="cm-f-warm" src="${SAMPLE}" alt="" width="320" height="240" loading="lazy"><span class="cm-f-saved">Warm · saved to Pics</span></div>
+ return `<figure class="cm-demo-filters" role="img" aria-label="Example: one picture in each of the camera's filters, with Warm picked and saved to Pics">
+<div class="cm-f-main"><img class="cm-f-warm" src="${SAMPLE}" alt="" width="320" height="240" loading="lazy"><span class="cm-f-saved">Example · Warm · saved to Pics</span></div>
<ul class="cm-f-strip">${thumbs}</ul>
<ul class="cm-f-strip">${thumbs}</ul>
</figure>`;
</figure>`;
}
}
new file mode 100644
new file mode 100644
@@ -0,0 +1,18 @@
@@ -0,0 +1,18 @@
+'use strict';
+// Cam's home scenes are illustrations on the sample picture: the camera list and grants are private to their owner, so
+// the public page must label them Example and never print a written-in viewer, camera name or count.
+const assert = require('assert');
+const views = require('../server/views');
+
+const page = views.home({});
+assert.ok(page.includes('Live · example'), 'the live frame says Example');
+assert.ok(page.includes('Example grant'), 'the grant says Example');
+assert.ok(page.includes('Example · Warm · saved to Pics'), 'the filter strip says Example');
+assert.ok(page.includes('a still is posted to the stream'), 'the chat line describes the action, not a person');
+assert.ok(!/@ada|\bada\b|Back garden|5 of 7 days|sun just touched the ridge/.test(page), 'no written-in viewer, camera name or count');
+
+// The signed-in flag only changes the link in the privacy rules; it must not put any camera or grant on the public page.
+const signedIn = views.home({ signedIn: true });
+assert.ok(signedIn.includes('href="/my"'), 'a signed-in owner gets the way to their cameras');
+assert.ok(!/Back garden|@ada|5 of 7 days/.test(signedIn), 'and still no private camera or grant is drawn');
+console.log('cam home: every scene is labelled Example and no written-in person, camera or count remains');
@@ -1,7 +1,7 @@
@@ -1,7 +1,7 @@
'use strict';
'use strict';
-// Cam's home shows the real thing (the owner, 10-31: placeholder pictures made the rooms look unfinished): a live frame
-// with the cam button's flash and the chat line it posts, a camera's one grant, and one picture through every filter the
-// camera app has, with the same CSS as the app, so the home can never show a filter the camera does not apply.
+// Cam's home shows the product on its sample picture, labelled Example: a live frame with the cam button's flash and the
+// chat line it posts, a camera's one grant, and one picture through every filter the camera app has, with the same CSS as
+// the app, so the home can never show a filter the camera does not apply.
const assert = require('assert');
const assert = require('assert');
const fs = require('fs');
const fs = require('fs');
const path = require('path');
const path = require('path');
@@ -21,10 +21,10 @@ for (const [id, filter] of Object.entries(app)) {
@@ -21,10 +21,10 @@ for (const [id, filter] of Object.entries(app)) {
}
}
const home = views.home({ signedIn: false });
const home = views.home({ signedIn: false });
-assert.ok(home.includes('class="cm-demo-live"') && home.includes('class="cm-live-flash"') && home.includes('caught a still'), 'a live still, shown');
-assert.ok(home.includes('class="cm-demo-grant"') && home.includes('can watch') && home.includes('Revoke'), 'a grant, shown');
+assert.ok(home.includes('class="cm-demo-live"') && home.includes('class="cm-live-flash"') && home.includes('a still is posted to the stream'), 'a live still, shown as an example');
+assert.ok(home.includes('class="cm-demo-grant"') && home.includes('One viewer') && home.includes('Revoke'), 'a grant, shown as an example');
assert.ok(home.includes('class="cm-demo-filters"'), 'the filters, shown');
assert.ok(home.includes('class="cm-demo-filters"'), 'the filters, shown');
for (const id of Object.keys(app)) assert.ok(home.includes(`class="cm-f-${id}"`), `the ${id} filter is in the strip`);
for (const id of Object.keys(app)) assert.ok(home.includes(`class="cm-f-${id}"`), `the ${id} filter is in the strip`);
assert.ok(!/<img src="\/img\/cam-shutter\.svg"/.test(home), 'no placeholder picture in a scene');
assert.ok(!/<img src="\/img\/cam-shutter\.svg"/.test(home), 'no placeholder picture in a scene');
assert.ok(!/<script/i.test(sample) && !/href=|xlink:/i.test(sample), 'the sample picture is a plain drawing');
assert.ok(!/<script/i.test(sample) && !/href=|xlink:/i.test(sample), 'the sample picture is a plain drawing');
-console.log(`cam home scenes: ${Object.keys(app).length} filters equal to the camera's, three real scenes`);
+console.log(`cam home scenes: ${Object.keys(app).length} filters equal to the camera's, three example scenes`);