Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
24 commits
Select commit Hold shift + click to select a range
eb6207d
feat(viewer): spa rewrite with drafts, flags, submissions, and vercel…
m5x5 May 19, 2026
b0e9e97
fix(deploy): use explicit per-route rewrites for vercel SPA fallback
m5x5 May 19, 2026
1cb1194
fix(deploy): disable cleanUrls so SPA rewrites take effect
m5x5 May 19, 2026
ab62385
feat(sync): mirror drafts, flags, and edit requests to the user's pod
m5x5 May 19, 2026
1ae0a85
feat(viewer): show profile photos and logos on cards
m5x5 May 20, 2026
fbbc2d2
feat(viewer): responsive layout for mobile
m5x5 May 20, 2026
ae1de76
fix(viewer): shrink header title on small screens instead of hiding
m5x5 May 20, 2026
87fb354
feat(viewer): record detail opens as bottom sheet on mobile
m5x5 May 20, 2026
de46f51
feat(viewer): hide section table of contents on mobile
m5x5 May 20, 2026
cdda5a7
feat(viewer): show all category items, status badges, and status filter
m5x5 May 20, 2026
b73828a
feat(viewer): move About into the profile menu
m5x5 May 20, 2026
dd3fb2e
fix(viewer): remove tap highlight and dedupe overlaid records by name
m5x5 May 20, 2026
fa8a7d7
feat(viewer): add development-version banner linking the official cat…
m5x5 May 20, 2026
2d97d1f
fix(viewer): use slotted SVG plus icon on new record button
m5x5 May 20, 2026
0b50df7
feat(viewer): dismissible dev banner, DM Sans, borderless cards, side…
m5x5 May 20, 2026
61d6451
feat(viewer): embed feedback-tracker widget
m5x5 May 20, 2026
a314d0e
feat(viewer): chip-slider categories, side sheet, status defaults, st…
m5x5 May 21, 2026
dbef069
feat(viewer): per-record Solid server compatibility reports with rela…
m5x5 May 22, 2026
e40c3a2
feat(notify): conditional form fields; show custom server only when O…
m5x5 May 22, 2026
7906456
feat(viewer): test reports get result scale + test type; fix notify m…
m5x5 May 22, 2026
b116ff4
feat(viewer): mobile hamburger menu, PWA manifest, in-sheet back button
m5x5 May 22, 2026
a4c1f5d
feat(viewer): mobile breadcrumb; match card border to avatars; cleanu…
m5x5 May 22, 2026
9dc22d9
feat(viewer): inline + Add pill in each section heading
m5x5 May 22, 2026
7e34914
feat(viewer): move log in / sign up to the mobile hamburger menu
m5x5 May 23, 2026
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 .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -16,3 +16,6 @@ catalog-shacl.ttl
/node_modules
/test/tmp
/.idea

dist/
.vercel
Binary file added assets/icon-192.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added assets/icon-512.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added assets/icon-maskable-512.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
82 changes: 82 additions & 0 deletions dev-server.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,82 @@
#!/usr/bin/env node
// Minimal static dev server with SPA fallback.
// Serves files from the project root; for any GET that does not resolve
// to an existing file (e.g. /apps, /learning), responds with index.html.

import http from 'node:http';
import fs from 'node:fs';
import path from 'node:path';
import { fileURLToPath } from 'node:url';

const root = path.dirname(fileURLToPath(import.meta.url));
const port = Number(process.env.PORT || 8765);

const MIME = {
'.html': 'text/html; charset=utf-8',
'.js': 'application/javascript; charset=utf-8',
'.mjs': 'application/javascript; charset=utf-8',
'.css': 'text/css; charset=utf-8',
'.json': 'application/json; charset=utf-8',
'.webmanifest': 'application/manifest+json; charset=utf-8',
'.svg': 'image/svg+xml',
'.png': 'image/png',
'.jpg': 'image/jpeg',
'.jpeg': 'image/jpeg',
'.gif': 'image/gif',
'.ico': 'image/x-icon',
'.ttl': 'text/turtle; charset=utf-8',
'.shce': 'text/plain; charset=utf-8',
'.txt': 'text/plain; charset=utf-8',
'.map': 'application/json; charset=utf-8',
'.woff': 'font/woff',
'.woff2':'font/woff2',
};

function safeJoin(base, p){
const target = path.normalize(path.join(base, p));
if(!target.startsWith(base)) return null;
return target;
}

function send(res, status, body, type='text/plain; charset=utf-8'){
res.writeHead(status, { 'Content-Type': type, 'Cache-Control': 'no-cache' });
res.end(body);
}

const server = http.createServer((req, res) => {
try {
const url = new URL(req.url, 'http://localhost');
const decoded = decodeURIComponent(url.pathname);
const target = safeJoin(root, decoded);
if(!target){ return send(res, 400, 'Bad path'); }

fs.stat(target, (err, stat) => {
if(!err && stat.isFile()){
const ext = path.extname(target).toLowerCase();
res.writeHead(200, { 'Content-Type': MIME[ext] || 'application/octet-stream', 'Cache-Control': 'no-cache' });
fs.createReadStream(target).pipe(res);
return;
}
// SPA fallback: serve index.html ONLY for top-level app routes (no `.`
// in the last segment, and not under /node_modules or /viewer where a
// missing file is a real 404). This avoids masking bad ESM imports.
const last = decoded.split('/').pop() || '';
const isAssetPath = decoded.startsWith('/node_modules/') ||
decoded.startsWith('/viewer/') ||
decoded.startsWith('/assets/');
if(!last.includes('.') && !isAssetPath){
const idx = path.join(root, 'index.html');
res.writeHead(200, { 'Content-Type': MIME['.html'], 'Cache-Control': 'no-cache' });
fs.createReadStream(idx).pipe(res);
return;
}
send(res, 404, 'Not found: ' + decoded);
});
} catch(e){
send(res, 500, String(e));
}
});

server.listen(port, () => {
console.log(`Solid Resources Catalog dev server: http://localhost:${port}/`);
});
Loading