openvibers/openvibe.wiki Commits
Empty states: an empty wiki space uses the shared kit (#294)
Changes
@@@ -257,6 +257,7 @@ function createPages({ svc, viewers, platform, config, log = console, limits, vititle: space.name, description: space.description || `${space.name}: a wiki on OpenVibe.Wiki.`, path: svc.spacePath(space),robots: open ? 'index, follow' : 'noindex, nofollow', cache: open ? 'public' : null,jsonLd: open ? seo.structuredData.breadcrumbs([{ name: 'Wiki', url: `${config.baseUrl}/` }, { name: space.name, url: `${config.baseUrl}${svc.spacePath(space)}` }]) : null,++ styles: ['kit.css'],});}));@@@ -304,9 +304,9 @@ function spacePage({ space, tree, canEdit, canManage, proposals }) {<section><h1>${space.name}</h1><p class="wk-muted">${space.kind === 'official' ? 'Official wiki' : 'Community wiki'} · ${VIS_LABEL[space.visibility]}</p>${space.description ? html`<p>${space.description}</p>` : ''}--${canEdit ? html`<p><a class="wk-button" href="/s/${e(space.slug)}/new">New page</a>${canManage ? html` <a href="/s/${e(space.slug)}/import">Import pages</a> <a href="/s/${e(space.slug)}/settings">Wiki settings</a>` : ''}</p>` : ''}++${canEdit ? html`<p class="wk-actions">${raw(kit.button({ href: `/s/${e(space.slug)}/new`, label: 'New page', icon: 'plus' }))}${canManage ? html` ${raw(kit.button({ href: `/s/${e(space.slug)}/import`, label: 'Import pages', icon: 'upload', kind: 'quiet' }))} ${raw(kit.button({ href: `/s/${e(space.slug)}/settings`, label: 'Wiki settings', icon: 'gear', kind: 'quiet' }))}` : ''}</p>` : ''}${proposals && proposals.length ? html`<p>${notice('info', `${proposals.length} AI proposal(s) wait for review.`)} <a href="/s/${e(space.slug)}/proposals">Review them</a></p>` : ''}--<h2>Pages</h2>${tree.length ? raw(treeHtml(tree, space)) : html`<p class="wk-muted">No pages yet.</p>`}++<h2>Pages</h2>${tree.length ? raw(treeHtml(tree, space)) : raw(kit.empty({ icon: 'book', title: 'No pages yet', text: canEdit ? 'Write the first page: a title, a few lines, and the wiki starts.' : 'The first page appears here once someone writes it.', action: canEdit ? { href: `/s/${e(space.slug)}/new`, label: 'Write the first page', icon: 'plus' } : null }))}${space.visibility === 'public' ? html`<p class="wk-muted">Follow this wiki: <a href="/s/${e(space.slug)}/feed.atom" type="application/atom+xml">Atom</a> · <a href="/s/${e(space.slug)}/feed.json" type="application/feed+json">JSON Feed</a></p>` : ''}</section>`;}@@@ -384,7 +384,7 @@ function discussionHtml(d, { space, page, actor }) {? html`<form method="post" action="${wpath(space, page)}/discuss" class="wk-form"><label for="wk-comment">Add a comment (posted to OpenVibe.Community as you)</label><textarea id="wk-comment" name="message" rows="3" maxlength="5000" required></textarea><button type="submit">Comment</button></form>`: html`<p><a href="/auth/login?next=${e(wpath(space, page))}">Sign in</a> to comment.</p>`;return html`<section class="wk-discussion" id="discussion">${head}--${comments.length ? html`<ul class="wk-comments">${comments.map((c) => html`<li><strong>${c.display_name || 'Someone'}</strong> <span class="wk-muted">${t(c.created_at)}${c.origin === 'ai' ? ' · AI' : ''}</span><p>${c.message}</p></li>`)}</ul>` : html`<p class="wk-muted">No comments yet.</p>`}++${comments.length ? html`<ul class="wk-comments">${comments.map((c) => html`<li><strong>${c.display_name || 'Someone'}</strong> <span class="wk-muted">${t(c.created_at)}${c.origin === 'ai' ? ' · AI' : ''}</span><p>${c.message}</p></li>`)}</ul>` : raw(kit.empty({ icon: 'chat', title: 'No comments yet', text: 'Start the discussion about this page.', action: actor && actor.subject ? { href: '#wk-comment', label: 'Write the first comment', icon: 'plus' } : { href: `/auth/login?next=${e(wpath(space, page))}`, label: 'Sign in to comment', icon: 'user' } }))}${form}</section>`;}nnew file mode 100644@@@ -0,0 +1,25 @@++'use strict';++// An empty wiki space is a kit empty state, not a bare muted line, and the actions that write the first page++// are kit buttons (openvibe-shared, 4.179.0+). The space route loads kit.css so the state is styled.++const assert = require('assert');++const views = require('../server/render/views');++const fs = require('fs');++const path = require('path');++++const space = { id: 's1', slug: 'demo', name: 'Demo wiki', kind: 'community', visibility: 'public', description: '' };++const edit = String(views.spacePage({ space, tree: [], canEdit: true, canManage: true, proposals: [] }));++assert.ok(edit.includes('class="ovk-empty"'), 'the shared kit empty state');++assert.ok(edit.includes('No pages yet'), 'it says what is empty');++assert.ok(edit.includes('Write the first page'), 'the next action is named');++assert.ok(/class="ovk-btn[^"]*"[^>]*href="\/s\/demo\/new"/.test(edit), 'and is a kit button');++assert.ok(/class="ovk-btn[^"]*"[^>]*href="\/s\/demo\/import"/.test(edit), 'Import pages is a kit button too');++assert.ok(/class="ovk-btn[^"]*"[^>]*href="\/s\/demo\/settings"/.test(edit), 'Wiki settings is a kit button too');++++const readOnly = String(views.spacePage({ space, tree: [], canEdit: false, canManage: false, proposals: [] }));++assert.ok(readOnly.includes('class="ovk-empty"') && readOnly.includes('No pages yet'), 'a reader sees the state');++assert.ok(!readOnly.includes('Write the first page'), 'with no action they cannot take');++++const pages = fs.readFileSync(path.join(__dirname, '..', 'server', 'http', 'pages.js'), 'utf8');++assert.ok(/styles: \['kit\.css'\]/.test(pages), 'the space page loads kit.css');++++console.log('empty states: the wiki space uses kit.empty and kit.button');
@@ -257,6 +257,7 @@ function createPages({ svc, viewers, platform, config, log = console, limits, vi
@@ -257,6 +257,7 @@ function createPages({ svc, viewers, platform, config, log = console, limits, vi
title: space.name, description: space.description || `${space.name}: a wiki on OpenVibe.Wiki.`, path: svc.spacePath(space),
title: space.name, description: space.description || `${space.name}: a wiki on OpenVibe.Wiki.`, path: svc.spacePath(space),
robots: open ? 'index, follow' : 'noindex, nofollow', cache: open ? 'public' : null,
robots: open ? 'index, follow' : 'noindex, nofollow', cache: open ? 'public' : null,
jsonLd: open ? seo.structuredData.breadcrumbs([{ name: 'Wiki', url: `${config.baseUrl}/` }, { name: space.name, url: `${config.baseUrl}${svc.spacePath(space)}` }]) : null,
jsonLd: open ? seo.structuredData.breadcrumbs([{ name: 'Wiki', url: `${config.baseUrl}/` }, { name: space.name, url: `${config.baseUrl}${svc.spacePath(space)}` }]) : null,
+ styles: ['kit.css'],
});
});
}));
}));
@@ -304,9 +304,9 @@ function spacePage({ space, tree, canEdit, canManage, proposals }) {
@@ -304,9 +304,9 @@ function spacePage({ space, tree, canEdit, canManage, proposals }) {
<section><h1>${space.name}</h1>
<section><h1>${space.name}</h1>
<p class="wk-muted">${space.kind === 'official' ? 'Official wiki' : 'Community wiki'} · ${VIS_LABEL[space.visibility]}</p>
<p class="wk-muted">${space.kind === 'official' ? 'Official wiki' : 'Community wiki'} · ${VIS_LABEL[space.visibility]}</p>
${space.description ? html`<p>${space.description}</p>` : ''}
${space.description ? html`<p>${space.description}</p>` : ''}
-${canEdit ? html`<p><a class="wk-button" href="/s/${e(space.slug)}/new">New page</a>${canManage ? html` <a href="/s/${e(space.slug)}/import">Import pages</a> <a href="/s/${e(space.slug)}/settings">Wiki settings</a>` : ''}</p>` : ''}
+${canEdit ? html`<p class="wk-actions">${raw(kit.button({ href: `/s/${e(space.slug)}/new`, label: 'New page', icon: 'plus' }))}${canManage ? html` ${raw(kit.button({ href: `/s/${e(space.slug)}/import`, label: 'Import pages', icon: 'upload', kind: 'quiet' }))} ${raw(kit.button({ href: `/s/${e(space.slug)}/settings`, label: 'Wiki settings', icon: 'gear', kind: 'quiet' }))}` : ''}</p>` : ''}
${proposals && proposals.length ? html`<p>${notice('info', `${proposals.length} AI proposal(s) wait for review.`)} <a href="/s/${e(space.slug)}/proposals">Review them</a></p>` : ''}
${proposals && proposals.length ? html`<p>${notice('info', `${proposals.length} AI proposal(s) wait for review.`)} <a href="/s/${e(space.slug)}/proposals">Review them</a></p>` : ''}
-<h2>Pages</h2>${tree.length ? raw(treeHtml(tree, space)) : html`<p class="wk-muted">No pages yet.</p>`}
+<h2>Pages</h2>${tree.length ? raw(treeHtml(tree, space)) : raw(kit.empty({ icon: 'book', title: 'No pages yet', text: canEdit ? 'Write the first page: a title, a few lines, and the wiki starts.' : 'The first page appears here once someone writes it.', action: canEdit ? { href: `/s/${e(space.slug)}/new`, label: 'Write the first page', icon: 'plus' } : null }))}
${space.visibility === 'public' ? html`<p class="wk-muted">Follow this wiki: <a href="/s/${e(space.slug)}/feed.atom" type="application/atom+xml">Atom</a> · <a href="/s/${e(space.slug)}/feed.json" type="application/feed+json">JSON Feed</a></p>` : ''}
${space.visibility === 'public' ? html`<p class="wk-muted">Follow this wiki: <a href="/s/${e(space.slug)}/feed.atom" type="application/atom+xml">Atom</a> · <a href="/s/${e(space.slug)}/feed.json" type="application/feed+json">JSON Feed</a></p>` : ''}
</section>`;
</section>`;
}
}
@@ -384,7 +384,7 @@ function discussionHtml(d, { space, page, actor }) {
@@ -384,7 +384,7 @@ function discussionHtml(d, { space, page, actor }) {
? html`<form method="post" action="${wpath(space, page)}/discuss" class="wk-form"><label for="wk-comment">Add a comment (posted to OpenVibe.Community as you)</label><textarea id="wk-comment" name="message" rows="3" maxlength="5000" required></textarea><button type="submit">Comment</button></form>`
? html`<form method="post" action="${wpath(space, page)}/discuss" class="wk-form"><label for="wk-comment">Add a comment (posted to OpenVibe.Community as you)</label><textarea id="wk-comment" name="message" rows="3" maxlength="5000" required></textarea><button type="submit">Comment</button></form>`
: html`<p><a href="/auth/login?next=${e(wpath(space, page))}">Sign in</a> to comment.</p>`;
: html`<p><a href="/auth/login?next=${e(wpath(space, page))}">Sign in</a> to comment.</p>`;
return html`<section class="wk-discussion" id="discussion">${head}
return html`<section class="wk-discussion" id="discussion">${head}
-${comments.length ? html`<ul class="wk-comments">${comments.map((c) => html`<li><strong>${c.display_name || 'Someone'}</strong> <span class="wk-muted">${t(c.created_at)}${c.origin === 'ai' ? ' · AI' : ''}</span><p>${c.message}</p></li>`)}</ul>` : html`<p class="wk-muted">No comments yet.</p>`}
+${comments.length ? html`<ul class="wk-comments">${comments.map((c) => html`<li><strong>${c.display_name || 'Someone'}</strong> <span class="wk-muted">${t(c.created_at)}${c.origin === 'ai' ? ' · AI' : ''}</span><p>${c.message}</p></li>`)}</ul>` : raw(kit.empty({ icon: 'chat', title: 'No comments yet', text: 'Start the discussion about this page.', action: actor && actor.subject ? { href: '#wk-comment', label: 'Write the first comment', icon: 'plus' } : { href: `/auth/login?next=${e(wpath(space, page))}`, label: 'Sign in to comment', icon: 'user' } }))}
${form}</section>`;
${form}</section>`;
}
}
new file mode 100644
new file mode 100644
@@ -0,0 +1,25 @@
@@ -0,0 +1,25 @@
+'use strict';
+// An empty wiki space is a kit empty state, not a bare muted line, and the actions that write the first page
+// are kit buttons (openvibe-shared, 4.179.0+). The space route loads kit.css so the state is styled.
+const assert = require('assert');
+const views = require('../server/render/views');
+const fs = require('fs');
+const path = require('path');
+
+const space = { id: 's1', slug: 'demo', name: 'Demo wiki', kind: 'community', visibility: 'public', description: '' };
+const edit = String(views.spacePage({ space, tree: [], canEdit: true, canManage: true, proposals: [] }));
+assert.ok(edit.includes('class="ovk-empty"'), 'the shared kit empty state');
+assert.ok(edit.includes('No pages yet'), 'it says what is empty');
+assert.ok(edit.includes('Write the first page'), 'the next action is named');
+assert.ok(/class="ovk-btn[^"]*"[^>]*href="\/s\/demo\/new"/.test(edit), 'and is a kit button');
+assert.ok(/class="ovk-btn[^"]*"[^>]*href="\/s\/demo\/import"/.test(edit), 'Import pages is a kit button too');
+assert.ok(/class="ovk-btn[^"]*"[^>]*href="\/s\/demo\/settings"/.test(edit), 'Wiki settings is a kit button too');
+
+const readOnly = String(views.spacePage({ space, tree: [], canEdit: false, canManage: false, proposals: [] }));
+assert.ok(readOnly.includes('class="ovk-empty"') && readOnly.includes('No pages yet'), 'a reader sees the state');
+assert.ok(!readOnly.includes('Write the first page'), 'with no action they cannot take');
+
+const pages = fs.readFileSync(path.join(__dirname, '..', 'server', 'http', 'pages.js'), 'utf8');
+assert.ok(/styles: \['kit\.css'\]/.test(pages), 'the space page loads kit.css');
+
+console.log('empty states: the wiki space uses kit.empty and kit.button');