Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions apps/server/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,9 @@ export async function boot(options: { port?: number; listen?: boolean } = {}) {
bundledRoot: join(REPO_ROOT, 'plugins'),
baseUrl,
});
if (new URL(baseUrl).hostname === 'bbs.hqtui.com') {
await registry.setEnabled('profullstack-footer', true);
}
const enabled = [...registry.enabled];
console.log(`[tsbb] plugins: ${enabled.length ? enabled.join(', ') : 'none enabled'}`);
for (const [slug, error] of registry.errors) console.warn(`[tsbb] plugin ${slug}: ${error}`);
Expand Down
51 changes: 24 additions & 27 deletions packages/ui/src/components/layout.ts
Original file line number Diff line number Diff line change
Expand Up @@ -106,6 +106,7 @@ function frontPageTitle(boardName: string, tagline?: string): string {
*/
export function Layout(props: LayoutProps) {
const slots = props.slots ?? {};
const universalFooter = slots.footer?.includes('data-pfs-footer') ?? false;
const theme = props.theme ?? 'system';
const themeColor = props.themeColor ?? { light: '#fffcf9', dark: '#1a120c' };
const title =
Expand Down Expand Up @@ -203,33 +204,29 @@ export function Layout(props: LayoutProps) {
${trusted(slots.header)}
</header>
<main class="main" id="main"><div class="container">${props.body}</div></main>
<footer class="site-footer">
${props.footerNav ? FooterColumns(props, props.footerNav) : ''}
<div class="container row-between footer-bottom">
<span>
&copy; ${new Date().getFullYear()} ${props.operator ?? 'Profullstack, Inc.'} &middot; running on
<a href="https://github.com/profullstack/tsbb" rel="noopener">tsbb</a>
</span>
<span class="row">
<a href="/about">About</a>
<a href="/members">Members</a>
<a href="/docs">Docs</a>
<a href="/feeds">Feeds</a>
<a href="/feed.xml">RSS</a>
<!--
A class, not a style attribute. style-src has no 'unsafe-inline',
which covers inline STYLE ATTRIBUTES as well as <style> blocks —
so this link's layout was refused by the board's own policy and
the icon sat above the word instead of beside it.
-->
<a class="footer-link" href="https://github.com/profullstack/tsbb" rel="noopener" title="tsbb on GitHub"
>${IconGithub()} GitHub</a
>
${props.viewer.isAdmin ? html`<a href="/admin">Admin</a>` : ''}
</span>
</div>
${trusted(slots.footer)}
</footer>
${universalFooter
? trusted(slots.footer)
: html`<footer class="site-footer">
${props.footerNav ? FooterColumns(props, props.footerNav) : ''}
<div class="container row-between footer-bottom">
<span>
&copy; ${new Date().getFullYear()} ${props.operator ?? 'Profullstack, Inc.'} &middot; running on
<a href="https://github.com/profullstack/tsbb" rel="noopener">tsbb</a>
</span>
<span class="row">
<a href="/about">About</a>
<a href="/members">Members</a>
<a href="/docs">Docs</a>
<a href="/feeds">Feeds</a>
<a href="/feed.xml">RSS</a>
<a class="footer-link" href="https://github.com/profullstack/tsbb" rel="noopener" title="tsbb on GitHub"
>${IconGithub()} GitHub</a
>
${props.viewer.isAdmin ? html`<a href="/admin">Admin</a>` : ''}
</span>
</div>
${trusted(slots.footer)}
</footer>`}
</div>
${trusted(slots.bodyEnd)}
</body>
Expand Down
2 changes: 1 addition & 1 deletion plugins/profullstack-footer/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
"type": "module",
"main": "./src/index.ts",
"dependencies": {
"@profullstack/footer": "^0.2.6",
"@profullstack/footer": "latest",
"@tsbb/plugin-api": "workspace:*"
}
}
2 changes: 1 addition & 1 deletion plugins/profullstack-footer/plugin.json
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
{
"slug": "profullstack-footer",
"name": "Profullstack Footer",
"description": "The Profullstack network footer: the << Profullstack >> webring row and the built.indie and pwamart badges. Off by default; for boards run by Profullstack.",
"description": "The shared Profullstack footer for the company board, with a remotely updated template and site-specific links.",
"author": "Profullstack, Inc.",
"homepage": "https://github.com/profullstack/footer",
"license": "MIT"
Expand Down
27 changes: 21 additions & 6 deletions plugins/profullstack-footer/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,8 @@ import { definePlugin } from '@tsbb/plugin-api';
import { footerHtml, latestTemplate } from '@profullstack/footer';

/**
* The Profullstack network footer (@profullstack/footer), for boards that
* Profullstack runs: the << Profullstack >> webring row, the built.indie and
* pwamart badges and the copyright line, under the board's own footer.
* The Profullstack network footer (@profullstack/footer), enabled on
* bbs.hqtui.com as the board's footer and optional on other boards.
*
* Ships DISABLED. Joining a webring and showing someone else's badges is the
* operator's choice, not something an upgrade should decide for every board.
Expand All @@ -23,15 +22,15 @@ import { footerHtml, latestTemplate } from '@profullstack/footer';
* the board without a redeploy.
*/

const BADGE_HOSTS = ['https://built.indie.pit.world', 'https://pwamart.com'];
const BADGE_HOSTS = ['https://logicsrc.com', 'https://profullstack.com'];

export default definePlugin({
manifest: {
slug: 'profullstack-footer',
name: 'Profullstack Footer',
version: '0.1.0',
description:
'The Profullstack network footer: webring row plus the built.indie and pwamart badges. Off by default; for boards run by Profullstack.',
'The shared Profullstack footer with a remotely updated template and site-specific links.',
author: 'Profullstack, Inc.',
homepage: 'https://github.com/profullstack/footer',
license: 'MIT',
Expand Down Expand Up @@ -74,7 +73,23 @@ export default definePlugin({
'layout:footer',
async () => {
const since = Number(ctx.settings.get('since') ?? 0);
return footerHtml({ site: site(), css: false, ...(since > 0 ? { since } : {}) });
const memberSite = site();
return footerHtml({
site: memberSite,
css: false,
subscribe: false,
builtIndieHref: `https://built.indie.pit.world/for?site=${memberSite}`,
pwamartHref: `https://pwamart.com/for?site=${memberSite}`,
links: [
{ label: 'About', href: '/about' },
{ label: 'Members', href: '/members' },
{ label: 'Docs', href: '/docs' },
{ label: 'Feeds', href: '/feeds' },
{ label: 'RSS', href: '/feed.xml' },
{ label: 'GitHub', href: 'https://github.com/profullstack/tsbb' },
],
...(since > 0 ? { since } : {}),
});
},
// Last in the footer, below anything another plugin puts there.
1000,
Expand Down
10 changes: 5 additions & 5 deletions pnpm-lock.yaml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

6 changes: 4 additions & 2 deletions test/plugins.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -120,8 +120,10 @@ describe('the plugin host', () => {
const response = await app.fetch(new Request(url('/')));
body = await response.text();
assert.ok(body.includes('rssamplifier.com/ring/profullstack'), 'the webring row is in the HTML');
assert.ok(body.includes('built.indie.pit.world/for.svg?site=https://tsbb.dev/'), 'built.indie badge');
assert.ok(body.includes('pwamart.com/for.svg'), 'pwamart badge');
assert.ok(body.includes('href="https://built.indie.pit.world/for?site=https://tsbb.dev/"'), 'built.indie badge link');
assert.ok(body.includes('src="https://logicsrc.com/openicon/set/hq/svg/built-indie.svg"'), 'built.indie icon');
assert.ok(body.includes('href="https://pwamart.com/for?site=https://tsbb.dev/"'), 'pwamart badge link');
assert.ok(body.includes('src="https://logicsrc.com/openicon/set/hq/svg/pwamart.svg"'), 'pwamart icon');
assert.ok(!/<style[^>]*>\.pfs-footer/.test(body), 'no inline footer style: style-src has no unsafe-inline');
assert.ok(body.includes('/p/profullstack-footer/footer.css'), 'the CSS comes from the board');

Expand Down
Loading