Skip to content
Open
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
10 changes: 10 additions & 0 deletions scripts/smoke-test.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -264,6 +264,16 @@ try {
await page.locator('.rail.open').getByRole('link', { name: 'Connect a repo' }).click();
await page.waitForURL('**/maintainer/submit');

// ------------------------------------------------------------- not-found UI
await go('/missing-route');
await page.getByRole('heading', { name: 'Page not found' }).waitFor();
assert.equal(await page.title(), 'Page not found | Parallax');
assert.ok(await page.getByRole('link', { name: /Explore issues/ }).isVisible());
assert.ok(await page.getByRole('link', { name: 'Home', exact: true }).isVisible());
await go('/issue/not-a-real-issue');
await page.getByRole('heading', { name: 'Issue not found' }).waitFor();
assert.equal(await page.title(), 'Issue not found | Parallax');

assert.deepEqual(errors, []);
console.log('Passed: public explore (no dashboard chrome), search/tabs/filters, contributor apply and persistence, separate maintainer sign-in, connect-then-verify gate, per-repo dashboards scoped by owner and verification, proposal assignment, posting a funded issue, payout address validation, merge-and-release writing a receipt, theme persistence, 15 routes at 5 widths with no overflow, and the mobile drawer.');
} catch (error) {
Expand Down
3 changes: 2 additions & 1 deletion src/App.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ import { canOpenRepoDashboard, escrowedTotal, formatMoney, repoName, reposOwnedB
import { PLATFORM } from './lib/platform';
import { Avatar, Brand, EASE } from './components/ui';
import { GooeyNav } from './components/bits';
import { NotFound } from './components/NotFound';
import { Landing } from './pages/landing';
import { Explore } from './pages/explore';
import { IssuePage } from './pages/issue';
Expand Down Expand Up @@ -381,7 +382,7 @@ function Routed() {
<Route path="/maintainer/repo/:repoId/issues" element={<RepoShell><RepoIssues /></RepoShell>} />
<Route path="/maintainer/repo/:repoId/settings" element={<RepoShell><RepoSettings /></RepoShell>} />

<Route path="*" element={<Navigate to="/" replace />} />
<Route path="*" element={<PublicShell><NotFound /></PublicShell>} />
</Routes>
);
}
Expand Down
31 changes: 31 additions & 0 deletions src/components/NotFound.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
import { useEffect } from 'react';
import { Link } from 'react-router-dom';
import { ArrowLeft, Home } from 'lucide-react';
import { Page } from './ui';

export function NotFound({ issue = false }: { issue?: boolean }) {
const title = issue ? 'Issue not found' : 'Page not found';

useEffect(() => {
document.title = `${title} | Parallax`;
return () => { document.title = 'Parallax — bounties settled on Stellar'; };
}, [title]);

return (
<Page className="not-found-page">
<section className="not-found-card" aria-labelledby="not-found-title">
<p className="label">404</p>
<h1 id="not-found-title">{title}</h1>
<p className="muted">
{issue
? 'That issue is not in the current Parallax preview.'
: 'That address does not match a Parallax page.'}
</p>
<div className="row wrap" style={{ gap: 8 }}>
<Link className="btn primary" to="/explore"><ArrowLeft size={14} />Explore issues</Link>
<Link className="btn" to="/"><Home size={14} />Home</Link>
</div>
</section>
</Page>
);
}
5 changes: 3 additions & 2 deletions src/pages/issue.tsx
Original file line number Diff line number Diff line change
@@ -1,10 +1,11 @@
import { useState } from 'react';
import { Link, Navigate, useNavigate, useParams } from 'react-router-dom';
import { Link, useNavigate, useParams } from 'react-router-dom';
import { ArrowUpRight, Check, GitPullRequest, Lock } from 'lucide-react';
import { applicantName, formatMoney, isOwnApplication, repoName, statusTone } from '../lib/model';
import { PLATFORM } from '../lib/platform';
import { useApp } from '../lib/store';
import { Avatar, Chip, Crumbs, Empty, ModalHost, Page } from '../components/ui';
import { NotFound } from '../components/NotFound';

export function IssuePage() {
const { issueId } = useParams();
Expand All @@ -15,7 +16,7 @@ export function IssuePage() {
const [err, setErr] = useState('');

const issue = state.issues.find(i => i.id === issueId);
if (!issue) return <Navigate to="/explore" replace />;
if (!issue) return <NotFound issue />;

const repo = state.repos.find(r => r.id === issue.repoId)!;
const me = state.session.contributor;
Expand Down
4 changes: 4 additions & 0 deletions src/styles/pages.css
Original file line number Diff line number Diff line change
Expand Up @@ -127,6 +127,10 @@ a.row-title:hover { text-decoration: underline; text-underline-offset: 2px; }
============================================================ */
.detail-grid { display: grid; grid-template-columns: minmax(0, 1fr) 280px; gap: var(--s7); align-items: start; }
.detail-head { padding-bottom: var(--s4); border-bottom: 1px solid var(--line); margin-bottom: var(--s5); }
.not-found-page { min-height: 65vh; display: grid; place-items: center; padding: var(--s8) var(--s4); }
.not-found-card { width: min(100%, 520px); padding: var(--s7); border: 1px solid var(--line); border-radius: var(--r4); background: var(--surface); }
.not-found-card h1 { margin: var(--s2) 0; }
.not-found-card > p:not(.label) { margin: 0 0 var(--s5); }
.detail-head h1 { margin: var(--s3) 0 var(--s3); font-size: var(--t7); line-height: 1.25; }
.prose h2 { font-size: var(--t5); margin-bottom: var(--s2); }
.prose h2 + p { font-size: var(--t4); color: var(--ink-2); }
Expand Down