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
66 changes: 66 additions & 0 deletions MIGRATION_PARITY.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,66 @@
# Astro Migration Parity Contract

This document defines the "must match" behaviors and routes to keep the Astro
migration safe and low-risk. Changes outside this list are deferred until after
cutover.

## Must Match

### Routes (trailing slash preserved)
- `/` (home)
- `/about/`
- `/faq/`
- `/projects/`
- `/projects/gazette-protocol/` (draft content; see Draft Handling)
- `/projects/the-truth-post/`
- `/projects/prove-me-wrong/` (draft content; see Draft Handling)
- `/404/` (404 page)

### Markdown Source + Frontmatter
Source files live in `src/pages/**/*.md` with frontmatter:
- `slug` (string, required)
- `draft` (boolean, optional)
- `toc` (boolean, optional)

### Draft Handling
Current Gatsby behavior hides drafts in all environments because `process.env.ENV`
is undefined. For parity-first, drafts should remain hidden in production and
preview unless we explicitly opt-in to show them.

### TOC Behavior
If `toc: true`, insert a list of `h2` headings immediately after the first `h1`.
Each entry links to the heading id (slugged).

### SEO + Metadata
- Canonical/OG/Twitter tags match the current `Seo` component.
- `og:url` and canonical should use the deployment base URL.
- Production base: `https://proveuswrong.io/`
- Preview base: `CF_PAGES_URL` (Cloudflare Pages)
- `og:image` defaults to the site icon (`src/images/icon.png`).

### Sitemap/Robots
- `sitemap.xml` available at `/sitemap.xml`
- `robots.txt` allows all (`User-agent: *`, `Allow: /`)

### Assets + Paths
- Static files in `static/` are served from the site root:
- `/pressKit.zip`
- `/link.svg`
- `/linkRed.svg`
- Image assets in `src/images/` are used by layout and About page.

### Styling
- SCSS modules and global styles must retain current visual output.

## Open Decisions (post-parity)
- PWA manifest/offline support (currently in Gatsby, can be reintroduced later).
- Whether drafts should be visible in preview builds.
- Whether to keep React components or rewrite to native Astro.

## Parity Check Results (Astro build)
- Routes rendered in `astro/dist`: `/`, `/about/`, `/faq/`, `/projects/`, `/projects/the-truth-post/`, `/404/`.
- Draft routes excluded from build output as expected (`/projects/gazette-protocol/`, `/projects/prove-me-wrong/`).
- TOC insertion verified on `/faq/` (list of `h2` links placed after first `h1`).
- SEO tags present on sampled pages (title, description, OG/Twitter, `og:url` uses `https://proveuswrong.io/`).
- Static assets verified in output root and `/images/` (press kit + icons + portraits).
- `sitemap.xml` now served as an index pointing to `/sitemap-0.xml` (fixes robots.txt parity).
24 changes: 24 additions & 0 deletions astro/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
# build output
dist/
# generated types
.astro/

# dependencies
node_modules/

# logs
npm-debug.log*
yarn-debug.log*
yarn-error.log*
pnpm-debug.log*


# environment variables
.env
.env.production

# macOS-specific files
.DS_Store

# jetbrains setting folder
.idea/
4 changes: 4 additions & 0 deletions astro/.vscode/extensions.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
{
"recommendations": ["astro-build.astro-vscode"],
"unwantedRecommendations": []
}
11 changes: 11 additions & 0 deletions astro/.vscode/launch.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
{
"version": "0.2.0",
"configurations": [
{
"command": "./node_modules/.bin/astro dev",
"name": "Development server",
"request": "launch",
"type": "node-terminal"
}
]
}
43 changes: 43 additions & 0 deletions astro/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
# Astro Starter Kit: Minimal

```sh
yarn create astro@latest -- --template minimal
```

> 🧑‍🚀 **Seasoned astronaut?** Delete this file. Have fun!

## 🚀 Project Structure

Inside of your Astro project, you'll see the following folders and files:

```text
/
├── public/
├── src/
│ └── pages/
│ └── index.astro
└── package.json
```

Astro looks for `.astro` or `.md` files in the `src/pages/` directory. Each page is exposed as a route based on its file name.

There's nothing special about `src/components/`, but that's where we like to put any Astro/React/Vue/Svelte/Preact components.

Any static assets, like images, can be placed in the `public/` directory.

## 🧞 Commands

All commands are run from the root of the project, from a terminal:

| Command | Action |
| :------------------------ | :----------------------------------------------- |
| `yarn install` | Installs dependencies |
| `yarn dev` | Starts local dev server at `localhost:4321` |
| `yarn build` | Build your production site to `./dist/` |
| `yarn preview` | Preview your build locally, before deploying |
| `yarn astro ...` | Run CLI commands like `astro add`, `astro check` |
| `yarn astro -- --help` | Get help using the Astro CLI |

## 👀 Want to learn more?

Feel free to check [our documentation](https://docs.astro.build) or jump into our [Discord server](https://astro.build/chat).
31 changes: 31 additions & 0 deletions astro/astro.config.mjs
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
// @ts-check
import { defineConfig } from "astro/config";
import cloudflare from "@astrojs/cloudflare";
import react from "@astrojs/react";
import sitemap from "@astrojs/sitemap";
import remarkTocAfterH1 from "./src/lib/remark-toc-after-h1.js";

const isProd =
process.env.CF_PAGES_ENVIRONMENT === "production" ||
process.env.NODE_ENV === "production";
const site =
process.env.SITE_URL ||
(isProd
? "https://proveuswrong.io"
: process.env.CF_PAGES_URL || "http://localhost:4321");

// https://astro.build/config
export default defineConfig({
build: {
format: "directory",
},
trailingSlash: "always",
site,
integrations: [react(), sitemap()],
adapter: cloudflare({
mode: "static",
}),
markdown: {
remarkPlugins: [remarkTocAfterH1],
},
});
26 changes: 26 additions & 0 deletions astro/package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
{
"name": "astro",
"type": "module",
"version": "0.0.1",
"scripts": {
"dev": "astro dev",
"build": "astro build",
"preview": "astro preview",
"astro": "astro"
},
"dependencies": {
"@astrojs/cloudflare": "^12.6.12",
"@astrojs/react": "^4.4.2",
"@astrojs/sitemap": "^3.6.0",
"astro": "^5.16.6",
"github-slugger": "^2.0.0",
"react": "^19.2.3",
"react-dom": "^19.2.3",
"sass": "^1.97.1",
"unist-util-visit": "^5.0.0"
},
"devDependencies": {
"@types/react": "^19",
"@types/react-dom": "^19"
}
}
99 changes: 99 additions & 0 deletions astro/src/components/Footer.jsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,99 @@
import * as React from "react";
import * as styles from "./footer.module.scss";
import githubIcon from "../icons/github.svg?raw";
import twitterIcon from "../icons/twitter.svg?raw";
import emailIcon from "../icons/email.svg?raw";
import angelIcon from "../icons/angel.svg?raw";
import discordIcon from "../icons/discord.svg?raw";
import linkedInIcon from "../icons/linkedin.svg?raw";
import pressKitIcon from "../icons/pressKit.svg?raw";

const InlineSvg = ({ svg, id }) => (
<span
aria-hidden="true"
id={id}
dangerouslySetInnerHTML={{ __html: svg }}
/>
);

const Footer = () => (
<footer>
<div className={styles.container}>
<div className={styles.social}>
<a
href="https://www.linkedin.com/company/prove-us-wrong/"
target="_blank"
rel="noopener noreferrer"
title='LinkedIn Company Page'
>
<span style={{ display: "none" }}>Link to LinkedIn profile</span>
<InlineSvg svg={linkedInIcon} id="linkedin" />
</a>
<a
href="https://angel.co/company/prove-us-wrong"
target="_blank"
rel="noopener noreferrer"
title='AngelList Page'
>
<span style={{ display: "none" }}>Link to AngelList profile</span>
<InlineSvg svg={angelIcon} id="angel" />
</a>

<a
href="https://twitter.com/ProveUsWrongIO"
target="_blank"
rel="noopener noreferrer"
title='Twitter Page'
>
<span style={{ display: "none" }}>Link to Twitter profile</span>
<InlineSvg svg={twitterIcon} id="twitter" />
</a>


<a
href="https://discord.gg/FvDrdDtYAV"
target="_blank"
rel="noopener noreferrer"
title='Discord Community'
>
<span style={{ display: "none" }}>Link to Discord community</span>
<InlineSvg svg={discordIcon} id="discord" />
</a>
<a
href="https://github.com/proveuswrong"
target="_blank"
rel="noopener noreferrer"
title='GitHub Organization'
>
<span style={{ display: "none" }}>Link to GitHub profile</span>
<InlineSvg svg={githubIcon} id="github" />
</a>

<a
href="mailto:inbox@proveuswrong.io"
target="_blank"
rel="noopener noreferrer"
title='E-mail Address'
>
<span style={{ display: "none" }}>Link to e-mail address</span>
<InlineSvg svg={emailIcon} id="email" />
</a>
<a
href="/pressKit.zip"
target="_blank"
rel="noopener noreferrer"
title='Press Kit'
>
<span style={{ display: "none" }}>Press Kit</span>
<InlineSvg svg={pressKitIcon} id="pressKit" />
</a>
</div>

<small>Copyright {new Date().getFullYear()} Prove Us Wrong</small>
<small>This site is powered by <a target="_blank" rel="noopener noreferrer" href="https://pages.cloudflare.com/">Cloudflare Pages</a></small>

</div>
</footer>
);

export default Footer;
27 changes: 27 additions & 0 deletions astro/src/components/Hamburger.jsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
import * as React from "react";

import * as styles from "./hamburger.module.scss";

const handleHamburgerClick = (e) => {
document.getElementById("toggle").classList.toggle(styles.active);

document.getElementById("overlay").classList.toggle("open");
};

const Hamburger = () => {
return (
<div
className={styles.button_container}
id="toggle"
onClick={handleHamburgerClick}
onKeyDown={handleHamburgerClick}
role="button"
>
<span className={styles.top}></span>
<span className={styles.middle}></span>
<span className={styles.bottom}></span>
</div>
);
};

export default Hamburger;
Loading