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
1 change: 1 addition & 0 deletions .astro/content-assets.mjs
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
export default new Map();
1 change: 1 addition & 0 deletions .astro/content-modules.mjs
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
export default new Map();
210 changes: 210 additions & 0 deletions .astro/content.d.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,210 @@
declare module 'astro:content' {
interface Render {
'.mdx': Promise<{
Content: import('astro').MDXContent;
headings: import('astro').MarkdownHeading[];
remarkPluginFrontmatter: Record<string, any>;
components: import('astro').MDXInstance<{}>['components'];
}>;
}
}

declare module 'astro:content' {
export interface RenderResult {
Content: import('astro/runtime/server/index.js').AstroComponentFactory;
headings: import('astro').MarkdownHeading[];
remarkPluginFrontmatter: Record<string, any>;
}
interface Render {
'.md': Promise<RenderResult>;
}

export interface RenderedContent {
html: string;
metadata?: {
imagePaths: Array<string>;
[key: string]: unknown;
};
}
}

declare module 'astro:content' {
type Flatten<T> = T extends { [K: string]: infer U } ? U : never;

export type CollectionKey = keyof AnyEntryMap;
export type CollectionEntry<C extends CollectionKey> = Flatten<AnyEntryMap[C]>;

export type ContentCollectionKey = keyof ContentEntryMap;
export type DataCollectionKey = keyof DataEntryMap;

type AllValuesOf<T> = T extends any ? T[keyof T] : never;
type ValidContentEntrySlug<C extends keyof ContentEntryMap> = AllValuesOf<
ContentEntryMap[C]
>['slug'];

export type ReferenceDataEntry<
C extends CollectionKey,
E extends keyof DataEntryMap[C] = string,
> = {
collection: C;
id: E;
};
export type ReferenceContentEntry<
C extends keyof ContentEntryMap,
E extends ValidContentEntrySlug<C> | (string & {}) = string,
> = {
collection: C;
slug: E;
};
export type ReferenceLiveEntry<C extends keyof LiveContentConfig['collections']> = {
collection: C;
id: string;
};

/** @deprecated Use `getEntry` instead. */
export function getEntryBySlug<
C extends keyof ContentEntryMap,
E extends ValidContentEntrySlug<C> | (string & {}),
>(
collection: C,
// Note that this has to accept a regular string too, for SSR
entrySlug: E,
): E extends ValidContentEntrySlug<C>
? Promise<CollectionEntry<C>>
: Promise<CollectionEntry<C> | undefined>;

/** @deprecated Use `getEntry` instead. */
export function getDataEntryById<C extends keyof DataEntryMap, E extends keyof DataEntryMap[C]>(
collection: C,
entryId: E,
): Promise<CollectionEntry<C>>;

export function getCollection<C extends keyof AnyEntryMap, E extends CollectionEntry<C>>(
collection: C,
filter?: (entry: CollectionEntry<C>) => entry is E,
): Promise<E[]>;
export function getCollection<C extends keyof AnyEntryMap>(
collection: C,
filter?: (entry: CollectionEntry<C>) => unknown,
): Promise<CollectionEntry<C>[]>;

export function getLiveCollection<C extends keyof LiveContentConfig['collections']>(
collection: C,
filter?: LiveLoaderCollectionFilterType<C>,
): Promise<
import('astro').LiveDataCollectionResult<LiveLoaderDataType<C>, LiveLoaderErrorType<C>>
>;

export function getEntry<
C extends keyof ContentEntryMap,
E extends ValidContentEntrySlug<C> | (string & {}),
>(
entry: ReferenceContentEntry<C, E>,
): E extends ValidContentEntrySlug<C>
? Promise<CollectionEntry<C>>
: Promise<CollectionEntry<C> | undefined>;
export function getEntry<
C extends keyof DataEntryMap,
E extends keyof DataEntryMap[C] | (string & {}),
>(
entry: ReferenceDataEntry<C, E>,
): E extends keyof DataEntryMap[C]
? Promise<DataEntryMap[C][E]>
: Promise<CollectionEntry<C> | undefined>;
export function getEntry<
C extends keyof ContentEntryMap,
E extends ValidContentEntrySlug<C> | (string & {}),
>(
collection: C,
slug: E,
): E extends ValidContentEntrySlug<C>
? Promise<CollectionEntry<C>>
: Promise<CollectionEntry<C> | undefined>;
export function getEntry<
C extends keyof DataEntryMap,
E extends keyof DataEntryMap[C] | (string & {}),
>(
collection: C,
id: E,
): E extends keyof DataEntryMap[C]
? string extends keyof DataEntryMap[C]
? Promise<DataEntryMap[C][E]> | undefined
: Promise<DataEntryMap[C][E]>
: Promise<CollectionEntry<C> | undefined>;
export function getLiveEntry<C extends keyof LiveContentConfig['collections']>(
collection: C,
filter: string | LiveLoaderEntryFilterType<C>,
): Promise<import('astro').LiveDataEntryResult<LiveLoaderDataType<C>, LiveLoaderErrorType<C>>>;

/** Resolve an array of entry references from the same collection */
export function getEntries<C extends keyof ContentEntryMap>(
entries: ReferenceContentEntry<C, ValidContentEntrySlug<C>>[],
): Promise<CollectionEntry<C>[]>;
export function getEntries<C extends keyof DataEntryMap>(
entries: ReferenceDataEntry<C, keyof DataEntryMap[C]>[],
): Promise<CollectionEntry<C>[]>;

export function render<C extends keyof AnyEntryMap>(
entry: AnyEntryMap[C][string],
): Promise<RenderResult>;

export function reference<C extends keyof AnyEntryMap>(
collection: C,
): import('astro/zod').ZodEffects<
import('astro/zod').ZodString,
C extends keyof ContentEntryMap
? ReferenceContentEntry<C, ValidContentEntrySlug<C>>
: ReferenceDataEntry<C, keyof DataEntryMap[C]>
>;
// Allow generic `string` to avoid excessive type errors in the config
// if `dev` is not running to update as you edit.
// Invalid collection names will be caught at build time.
export function reference<C extends string>(
collection: C,
): import('astro/zod').ZodEffects<import('astro/zod').ZodString, never>;

type ReturnTypeOrOriginal<T> = T extends (...args: any[]) => infer R ? R : T;
type InferEntrySchema<C extends keyof AnyEntryMap> = import('astro/zod').infer<
ReturnTypeOrOriginal<Required<ContentConfig['collections'][C]>['schema']>
>;

type ContentEntryMap = {

};

type DataEntryMap = {

};

type AnyEntryMap = ContentEntryMap & DataEntryMap;

type ExtractLoaderTypes<T> = T extends import('astro/loaders').LiveLoader<
infer TData,
infer TEntryFilter,
infer TCollectionFilter,
infer TError
>
? { data: TData; entryFilter: TEntryFilter; collectionFilter: TCollectionFilter; error: TError }
: { data: never; entryFilter: never; collectionFilter: never; error: never };
type ExtractDataType<T> = ExtractLoaderTypes<T>['data'];
type ExtractEntryFilterType<T> = ExtractLoaderTypes<T>['entryFilter'];
type ExtractCollectionFilterType<T> = ExtractLoaderTypes<T>['collectionFilter'];
type ExtractErrorType<T> = ExtractLoaderTypes<T>['error'];

type LiveLoaderDataType<C extends keyof LiveContentConfig['collections']> =
LiveContentConfig['collections'][C]['schema'] extends undefined
? ExtractDataType<LiveContentConfig['collections'][C]['loader']>
: import('astro/zod').infer<
Exclude<LiveContentConfig['collections'][C]['schema'], undefined>
>;
type LiveLoaderEntryFilterType<C extends keyof LiveContentConfig['collections']> =
ExtractEntryFilterType<LiveContentConfig['collections'][C]['loader']>;
type LiveLoaderCollectionFilterType<C extends keyof LiveContentConfig['collections']> =
ExtractCollectionFilterType<LiveContentConfig['collections'][C]['loader']>;
type LiveLoaderErrorType<C extends keyof LiveContentConfig['collections']> = ExtractErrorType<
LiveContentConfig['collections'][C]['loader']
>;

export type ContentConfig = typeof import("../src/content.config.mjs");
export type LiveContentConfig = never;
}
1 change: 1 addition & 0 deletions .astro/data-store.json
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
[["Map",1,2],"meta::meta",["Map",3,4,5,6],"astro-version","5.17.1","astro-config-digest","{\"root\":{},\"srcDir\":{},\"publicDir\":{},\"outDir\":{},\"cacheDir\":{},\"site\":\"https://compsoc.tech\",\"compressHTML\":true,\"base\":\"/\",\"trailingSlash\":\"ignore\",\"output\":\"static\",\"scopedStyleStrategy\":\"attribute\",\"build\":{\"format\":\"directory\",\"client\":{},\"server\":{},\"assets\":\"_astro\",\"serverEntry\":\"entry.mjs\",\"redirects\":true,\"inlineStylesheets\":\"auto\",\"concurrency\":1},\"server\":{\"open\":false,\"host\":false,\"port\":4321,\"streaming\":true,\"allowedHosts\":[]},\"redirects\":{},\"image\":{\"endpoint\":{\"route\":\"/_image\"},\"service\":{\"entrypoint\":\"astro/assets/services/sharp\",\"config\":{}},\"domains\":[],\"remotePatterns\":[],\"responsiveStyles\":false},\"devToolbar\":{\"enabled\":true},\"markdown\":{\"syntaxHighlight\":{\"type\":\"shiki\",\"excludeLangs\":[\"math\"]},\"shikiConfig\":{\"langs\":[],\"langAlias\":{},\"theme\":\"github-dark\",\"themes\":{},\"wrap\":false,\"transformers\":[]},\"remarkPlugins\":[],\"rehypePlugins\":[],\"remarkRehype\":{},\"gfm\":true,\"smartypants\":true},\"security\":{\"checkOrigin\":true,\"allowedDomains\":[]},\"env\":{\"schema\":{},\"validateSecrets\":false},\"experimental\":{\"clientPrerender\":false,\"contentIntellisense\":false,\"headingIdCompat\":false,\"preserveScriptOrder\":false,\"liveContentCollections\":false,\"csp\":false,\"staticImportMetaEnv\":false,\"chromeDevtoolsWorkspace\":false,\"failOnPrerenderConflict\":false,\"svgo\":false},\"legacy\":{\"collections\":false}}"]
Copy link

Copilot AI Feb 2, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The .astro directory (including files like this one) is a build/cache artifact generated by Astro and contains environment-specific metadata; committing it to the repo will cause unnecessary churn and potential type mismatches between developers. It would be better to remove .astro from version control and add it to .gitignore, regenerating it locally via the Astro tooling as needed.

Suggested change
[["Map",1,2],"meta::meta",["Map",3,4,5,6],"astro-version","5.17.1","astro-config-digest","{\"root\":{},\"srcDir\":{},\"publicDir\":{},\"outDir\":{},\"cacheDir\":{},\"site\":\"https://compsoc.tech\",\"compressHTML\":true,\"base\":\"/\",\"trailingSlash\":\"ignore\",\"output\":\"static\",\"scopedStyleStrategy\":\"attribute\",\"build\":{\"format\":\"directory\",\"client\":{},\"server\":{},\"assets\":\"_astro\",\"serverEntry\":\"entry.mjs\",\"redirects\":true,\"inlineStylesheets\":\"auto\",\"concurrency\":1},\"server\":{\"open\":false,\"host\":false,\"port\":4321,\"streaming\":true,\"allowedHosts\":[]},\"redirects\":{},\"image\":{\"endpoint\":{\"route\":\"/_image\"},\"service\":{\"entrypoint\":\"astro/assets/services/sharp\",\"config\":{}},\"domains\":[],\"remotePatterns\":[],\"responsiveStyles\":false},\"devToolbar\":{\"enabled\":true},\"markdown\":{\"syntaxHighlight\":{\"type\":\"shiki\",\"excludeLangs\":[\"math\"]},\"shikiConfig\":{\"langs\":[],\"langAlias\":{},\"theme\":\"github-dark\",\"themes\":{},\"wrap\":false,\"transformers\":[]},\"remarkPlugins\":[],\"rehypePlugins\":[],\"remarkRehype\":{},\"gfm\":true,\"smartypants\":true},\"security\":{\"checkOrigin\":true,\"allowedDomains\":[]},\"env\":{\"schema\":{},\"validateSecrets\":false},\"experimental\":{\"clientPrerender\":false,\"contentIntellisense\":false,\"headingIdCompat\":false,\"preserveScriptOrder\":false,\"liveContentCollections\":false,\"csp\":false,\"staticImportMetaEnv\":false,\"chromeDevtoolsWorkspace\":false,\"failOnPrerenderConflict\":false,\"svgo\":false},\"legacy\":{\"collections\":false}}"]
{}

Copilot uses AI. Check for mistakes.
5 changes: 5 additions & 0 deletions .astro/settings.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
{
"_variables": {
"lastUpdateCheck": 1770023553342
}
}
2 changes: 2 additions & 0 deletions .astro/types.d.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
/// <reference types="astro/client" />
/// <reference path="content.d.ts" />
5 changes: 3 additions & 2 deletions .github/workflows/build.yml
Original file line number Diff line number Diff line change
Expand Up @@ -12,13 +12,14 @@ jobs:
node-version: [20.x]

steps:
- uses: actions/checkout@v1
- uses: actions/checkout@v4
- name: Install pnpm
uses: pnpm/action-setup@v4
- name: Use Node.js ${{ matrix.node-version }}
uses: actions/setup-node@v1
uses: actions/setup-node@v4
with:
node-version: ${{ matrix.node-version }}
cache: 'pnpm'
- name: npm install and build
run: |
pnpm install
Expand Down
65 changes: 65 additions & 0 deletions PR_NOTES.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,65 @@
# Pull Request - Astro 5 Migration & Critical Fixes

## Summary

This PR updates the project to use Astro 5 and updates outdated dependencies.

Astro is super fast for page loading - I've tested it as much as possible - the only thing I can't test is the netlify stuff - but that hasnt changed so should be fine.

Let me know if you'd prefer any other changes.

All builds pass with 0 errors, 0 warnings.

## Key Changes

### Improvements
- **Faster page loads** - Astro's partial hydration only loads JavaScript for interactive components
- **Better SEO** - Static HTML generation with automatic sitemap
- **Smaller bundle sizes** - Ships less JavaScript to the browser
- **Modern architecture** - File-based routing with `.astro` components and React islands
- **Improved DX** - Built-in TypeScript support, better dev server, faster builds

### Framework & Dependencies
- **Astro**: none → 5.17.1
- **TypeScript**: 5.6.2 → 5.9.3
- **FontAwesome**: v5 → v6 (with react-fontawesome v3)
- **Removed unused packages**: `@typeform/embed`, `@types/jest`, `@types/classnames`, `react-helmet`, `@fortawesome/fontawesome-free`

### ⚙️ Configuration
- **Netlify**: Added `[build]` section to `netlify.toml` for proper deployment
- **GitHub Actions**: Updated to v4 actions with pnpm caching
- **README**: Updated for Astro architecture

## Testing Done

- ✅ Build succeeds: `pnpm run build` (0 errors, 0 warnings, 0 hints)
- ✅ Development server works: `pnpm run dev`
- ✅ TypeScript check passes: `astro check`
- ✅ All 11 pages generate correctly
- ✅ Sitemap generates at `/sitemap-index.xml`
- ✅ Netlify form attributes verified in build output (`data-netlify="true"`, `data-netlify-recaptcha="true"`)
- ✅ All redirects preserved in `netlify.toml`

## Post-Deployment Testing Required

**Contact Forms:**
1. Visit `/contact` and submit test form
2. Verify reCAPTCHA widget appears and validates
3. Check Netlify Forms dashboard for submission

**Redirects:**
Test these still work: `/join`, `/discord`, `/fb`, `/ins`, `/linkedin`, `/about`, `/sponsorshipdeck`

## Intentionally Not Updated

| Package | Reason |
|---------|--------|
| `wow.js` | Deprecated but functional; AOS replacement would require refactoring |
| `React 18 → 19` | React 19 very new (Dec 2024); staying on 18 for stability |
| `FontAwesome 6 → 7` | v7 has significant breaking changes |
| `react-google-recaptcha 2 → 3` | v3 has breaking API changes |

## Files Changed
- Modified: 9 component/layout files, `netlify.toml`, `.github/workflows/build.yml`, `README.md`, `package.json`
- Removed: `index.html`, `src/vite-env.d.ts` (old Vite files)

9 changes: 5 additions & 4 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -58,7 +58,7 @@ But it's the same folder? Why have the files changed? That's git at work. For mo

## Node and NPM

The website's back end runs on the [nodejs](https://nodejs.org/en/) runtime. Head over to https://nodejs.org/en/download/ and download the LTS (long term support) version for your platform.
The website runs on the [nodejs](https://nodejs.org/en/) runtime with [Astro](https://astro.build/) as the framework. Head over to https://nodejs.org/en/download/ and download the LTS (long term support) version for your platform.

Once installed, run

Expand Down Expand Up @@ -109,8 +109,9 @@ The site's main code is in `src/components`. Quite a lot of static assets are in

Be aware that we use some extra stuff to make developing the site a bit more fun:

- For JavaScript, we use TypeScript (which is why files have the extension `.tsx`). It's just JavaScript, but things have types. If you haven't used TypeScript before, check out https://www.typescriptlang.org/docs/handbook/typescript-in-5-minutes.html.
- For CSS, we use Sass (in `.scss` files). It's just like CSS, but you can nest things and define $variables. If you haven't used Sass before, check out https://sass-lang.com/guide.
- For the site, we use React. This lets us split the code up into separate components.
- **Astro** - The site framework that handles routing, SSR, and page layouts. Pages are in `src/pages/` using file-based routing. Learn more at https://docs.astro.build/
- **React** - Used for interactive components (with `client:load` directives). Components are in `src/components/`.
- **TypeScript** - All code uses TypeScript (`.tsx` files for React, `.astro` for Astro components). It's just JavaScript, but things have types. If you haven't used TypeScript before, check out https://www.typescriptlang.org/docs/handbook/typescript-in-5-minutes.html.
- **Sass** - For styling (`.scss` files). It's just like CSS, but you can nest things and define $variables. If you haven't used Sass before, check out https://sass-lang.com/guide.

As an aside, running `pnpm run build` will generate a folder called `dist` containing all the final HTML files we should host in production.
28 changes: 28 additions & 0 deletions astro.config.mjs
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
import { defineConfig } from 'astro/config';
import react from '@astrojs/react';
import sitemap from '@astrojs/sitemap';
import mdx from '@astrojs/mdx';

// https://astro.build/config
export default defineConfig({
site: 'https://compsoc.tech',
integrations: [
react(),
sitemap(),
mdx(),
],
vite: {
css: {
preprocessorOptions: {
scss: {
api: 'modern-compiler'
}
}
}
},
output: 'static',
build: {
inlineStylesheets: 'auto',
},
compressHTML: true,
});
Loading
Loading