Skip to content

Commit e1d3174

Browse files
Twissiclaude
andauthored
Deploy website using GitHub pages (#220)
* Convert website to static GitHub Pages deployment - Remove German language support, keep only English - Configure Next.js for static export with GitHub Pages basePath support - Add asset path utility function for proper GitHub Pages URL handling - Update all hardcoded asset paths to use dynamic basePath - Fix font URLs to work with GitHub Pages - Add .nojekyll file to prevent GitHub Pages from ignoring _next files - Update package.json with export script - Remove German translation files and city data - Format code with prettier 🤖 Generated with [Claude Code](https://claude.ai/code) Co-Authored-By: Claude <noreply@anthropic.com> * Remove Vercel deployment configuration 🤖 Generated with [Claude Code](https://claude.ai/code) Co-Authored-By: Claude <noreply@anthropic.com> * Replace Vercel workflow with GitHub Pages deployment - Remove Vercel-specific GitHub Actions workflow - Add GitHub Pages deployment workflow with proper Next.js static export - Configure automatic deployment on push to master/main branches - Use GitHub's official actions for Pages deployment 🤖 Generated with [Claude Code](https://claude.ai/code) Co-Authored-By: Claude <noreply@anthropic.com> * Fix ESLint configuration for styled-jsx and dev server - Add ignore rules for styled-jsx properties (jsx, global) - Disable explicit-module-boundary-types warnings - Fix React version detection in ESLint settings - Resolves dev server startup issues with linting errors 🤖 Generated with [Claude Code](https://claude.ai/code) Co-Authored-By: Claude <noreply@anthropic.com> * Add github-pages-new branch to deployment workflow - Include github-pages-new branch in GitHub Pages workflow triggers - Allows testing deployment from feature branch before merging 🤖 Generated with [Claude Code](https://claude.ai/code) Co-Authored-By: Claude <noreply@anthropic.com> * Update GitHub Actions to latest versions - Update actions/upload-pages-artifact from v2 to v3 - Update actions/deploy-pages from v2 to v4 - Fixes deprecated action version errors 🤖 Generated with [Claude Code](https://claude.ai/code) Co-Authored-By: Claude <noreply@anthropic.com> * Fix static export configuration for GitHub Pages - Add 'output: export' to next.config.js - Ensures out/ directory is generated during build - Fixes GitHub Actions artifact creation error 🤖 Generated with [Claude Code](https://claude.ai/code) Co-Authored-By: Claude <noreply@anthropic.com> * Fix static export for Next.js 12 and GitHub Pages - Remove output: 'export' config (Next.js 12 doesn't support it) - Update export script to run 'next build && next export' - Convert getInitialProps to getStaticProps/getStaticPaths for cities - Remove getInitialProps from withLocale container and _document - Fix data serialization in cities getStaticProps - Update GitHub Actions workflow to use export command - Successfully generates static files in out/ directory 🤖 Generated with [Claude Code](https://claude.ai/code) Co-Authored-By: Claude <noreply@anthropic.com> * Fix hardcoded image paths for GitHub Pages deployment Update all remaining hardcoded asset paths to use assetPath utility for proper GitHub Pages basePath support: - CityHero component background images - Meta component favicons and manifest links - MarkdownTeam component member images - Cities page social icons and about images 🤖 Generated with [Claude Code](https://claude.ai/code) Co-Authored-By: Claude <noreply@anthropic.com> * Fix font paths for GitHub Pages basePath support Update global CSS font declarations to use dynamic basePath for GitHub Pages deployment: - Add environment detection for GitHub Actions - Use GITHUB_REPOSITORY to extract repository name for basePath - Apply basePath to OpenSans, Roboto, and Material Icons font URLs - Ensures fonts load correctly when deployed with basePath on GitHub Pages 🤖 Generated with [Claude Code](https://claude.ai/code) Co-Authored-By: Claude <noreply@anthropic.com> * Update README with GitHub Pages deployment instructions - Replace outdated Zeit.co deployment information - Add detailed instructions for building with GitHub Pages basePath locally - Include environment variables needed for proper GitHub Pages build - Explain difference between local and GitHub Pages builds - Document asset path behavior with basePath configuration 🤖 Generated with [Claude Code](https://claude.ai/code) Co-Authored-By: Claude <noreply@anthropic.com> * Remove Slack references from README - Remove Slack channel mentions from contribution guidelines - Replace Slack communication with GitHub issue discussions - Encourage using GitHub issues for help and collaboration - Simplify communication channels to focus on GitHub-based workflow 🤖 Generated with [Claude Code](https://claude.ai/code) Co-Authored-By: Claude <noreply@anthropic.com> * Fix client-side navigation font loading issue Add font preloading to _document.tsx to ensure fonts are cached during initial page load, preventing FOUT during client-side navigation. The preload links use environment-aware basePath detection for proper GitHub Pages deployment. 🤖 Generated with [Claude Code](https://claude.ai/code) Co-Authored-By: Claude <noreply@anthropic.com> * Update branch in deploy config * Make build-time env vars available during runtime * Make custom domain configurable in deploy config * Prepare for custom domain * CR --------- Co-authored-by: Claude <noreply@anthropic.com>
1 parent bb76eea commit e1d3174

29 files changed

Lines changed: 308 additions & 352 deletions

.eslintrc.js

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -38,9 +38,13 @@ module.exports = {
3838
'@typescript-eslint/explicit-function-return-type': 0,
3939
'@typescript-eslint/member-delimiter-style': 0,
4040
'@typescript-eslint/no-explicit-any': 0,
41+
'@typescript-eslint/explicit-module-boundary-types': 'off',
42+
'react/no-unknown-property': ['error', { ignore: ['jsx', 'global'] }],
4143
},
4244
settings: {
43-
react: 'detect',
45+
react: {
46+
version: 'detect',
47+
},
4448
},
4549
overrides: [
4650
{
Lines changed: 55 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,55 @@
1+
name: Deploy to GitHub Pages
2+
3+
on:
4+
push:
5+
branches:
6+
- master
7+
8+
permissions:
9+
contents: read
10+
pages: write
11+
id-token: write
12+
13+
concurrency:
14+
group: "pages"
15+
cancel-in-progress: false
16+
17+
jobs:
18+
build:
19+
runs-on: ubuntu-latest
20+
steps:
21+
- name: Checkout
22+
uses: actions/checkout@v4
23+
24+
- name: Setup Node.js
25+
uses: actions/setup-node@v4
26+
with:
27+
node-version: '18'
28+
cache: 'npm'
29+
30+
- name: Install dependencies
31+
run: npm ci
32+
33+
- name: Build static site
34+
run: npm run export
35+
env:
36+
GITHUB_ACTIONS: true
37+
GITHUB_REPOSITORY: ${{ github.repository }}
38+
# Set CUSTOM_DOMAIN=true when using custom domain (e.g., opentechschool.org)
39+
CUSTOM_DOMAIN: true
40+
41+
- name: Upload artifact
42+
uses: actions/upload-pages-artifact@v3
43+
with:
44+
path: ./out
45+
46+
deploy:
47+
environment:
48+
name: github-pages
49+
url: ${{ steps.deployment.outputs.page_url }}
50+
runs-on: ubuntu-latest
51+
needs: build
52+
steps:
53+
- name: Deploy to GitHub Pages
54+
id: deployment
55+
uses: actions/deploy-pages@v4

.github/workflows/deploy.yml

Lines changed: 0 additions & 66 deletions
This file was deleted.

.gitignore

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,8 +2,10 @@ node_modules
22
src/.next
33
.env
44
src/out/
5+
out/
56
.DS_Store
67
npm-debug.log
78
next-env.d.ts
89
.next
910
.vercel
11+
.claude/

README.md

Lines changed: 49 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -25,11 +25,11 @@ If you want to contribute but don't know on what to work on, check our github is
2525

2626
If you are beginner, search for the label `good first issues`.<br />
2727
Assign the issue to your self and when you are done, make a PR to review.<br />
28-
Always feel free to reach out for help. You can write in the issue it self, you can open a PR as draft and ask suggestion about your code or you can contact us on [slack](https://opentechschool-slack.herokuapp.com) in the #website-dev channel.
28+
Always feel free to reach out for help. You can write in the issue itself, you can open a PR as draft and ask suggestion about your code.
2929

30-
### Requisit:
30+
### Requirements:
3131

32-
`Node version > 9`
32+
`Node version >= 12` (recommended: Node 18+ or 20+)
3333

3434
`npm`
3535

@@ -71,9 +71,8 @@ WrappedIcon.muiName = Icon.muiName;
7171

7272
## Cities data
7373

74-
Markdown for city can be found in data/cities.<br />
75-
Inside this folder you will find subfolders based on language. Each city must have at least english language to be visible.<br />
76-
Add as many language as you wish for your city. The files must have always the same name: `city-name.md`.<br />
74+
Markdown for city can be found in `data/cities/en/`.<br />
75+
Each city file should be named `city-name.md` and placed in the English directory.<br />
7776
If you want to add a city that is currently inactive, just add `is_inactive` to the markdown.
7877

7978
Each city **MUST HAVE**:
@@ -116,26 +115,21 @@ members:
116115

117116
### Translation
118117

119-
Translation are located in `translations/`. Here there are some configuration and typescript file needed to make translation works but most important there are `json` files for each language.<br />
120-
Those are translation for all the website except the city page.<br />
121-
If you create new content, please remember to add your text to those files, at least to the english translation.
118+
Translations are located in `translations/` directory. The website currently supports English only after the conversion to static site generation.<br />
119+
If you create new content, please remember to add your text to the `en.json` translation file.
122120

123-
If you add a new language add a `yourLanguage.json` file in the `translations/` directory and remember to add your language to the `config.ts` files to make it available to the `<LocalSwitcher />`
121+
To use translations in a component, use the `t()` function from the `useTranslation` hook:
124122

125-
If you want to use translation in a file, you can use the `t()` function, which it takes as a argument the string to translate from the language jons file.<br />
126-
Example:
127-
In my `en.json` i have such string:
123+
```javascript
124+
import useTranslation from '../hooks/useTranslation'
128125

129-
```
130-
"about": {
131-
"title": "About OTS"
126+
const MyComponent = () => {
127+
const { t } = useTranslation()
128+
return <h1>{t('about.title')}</h1>
132129
}
133130
```
134131

135-
in my `about.tsx` page i can use the `t` function like that: `t('about.title')`.
136-
`t()` function always fall back to english. If the translation doesn't exists even in the `en.json` file, you will see printed the string of your translation (i.e. `about.title`) and a warning will show up in your console.
137-
138-
`t()` function can be extracted form the `useTranslation` hook and in order to be effective in a page, the page must be wrapped with the `WithLocale()` HOC.
132+
The `t()` function takes a key from the `en.json` file and falls back to displaying the key if translation is missing.
139133

140134
### Conventions
141135

@@ -151,7 +145,40 @@ Yet, we avoid using javascript-in-css as much as possible therefore it will be e
151145

152146
## Deployment
153147

154-
This website is being deployed to [Zeit.co](https://zeit.co/) on the free team account https://zeit.co/opentechschool. Every push to master goes live automatically via their Github integration.
148+
This website is deployed to GitHub Pages. Every push to the `github-pages-new` branch automatically triggers the GitHub Actions workflow that builds and deploys the static site.
149+
150+
### Building for GitHub Pages Locally
151+
152+
To test the GitHub Pages build locally with the correct basePath configuration:
153+
154+
Note: We are using `out` instead of `websitenext`, but the github action will copy files from `out` to `websitenext`
155+
156+
```bash
157+
# Build and export with GitHub Pages environment variables
158+
GITHUB_ACTIONS=true GITHUB_REPOSITORY=OpenTechSchool/out npm run build
159+
GITHUB_ACTIONS=true GITHUB_REPOSITORY=OpenTechSchool/out npx next export
160+
161+
# The static files will be generated in the 'out' directory
162+
# All asset paths (images, fonts, links) will include the /out basePath
163+
```
164+
165+
**Important:** When building for GitHub Pages, the build process:
166+
167+
- Adds `/websitenext` basePath to all asset URLs
168+
- Configures static export for proper GitHub Pages deployment
169+
- Ensures fonts, images, and internal links work correctly with the repository's subpath
170+
171+
For local development without basePath, use the standard commands:
172+
173+
```bash
174+
npm run dev # Development server
175+
npm run build # Production build (local)
176+
npm run export # Static export (local)
177+
```
178+
179+
### Using a custom domain
180+
181+
Set `CUSTOM_DOMAIN` to true in `deploy-github-pages.yml` when using a custom domain e.g. opentechschool.org
155182

156183
## Contact
157184

@@ -161,4 +188,4 @@ Feel free to open a new issue here on github. Try to label it as best as you can
161188
Have an idea and already know how to develop it? Go ahead and make a PR, we are very happy to review it.
162189

163190
Have an idea but would like to talk to someone to know how to better proceed?
164-
Join us on [slack](https://opentechschool-slack.herokuapp.com): channel #website-dev
191+
Feel free to open a GitHub issue to discuss your ideas and get guidance on implementation.

components/CityHero/CityHero.tsx

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,9 +6,11 @@ import { mediaquery } from '../../style/style'
66
// import Link from 'next/link'
77
// import OutlineButton from '../Button/OutlineButton'
88
import useTranslation from '../../hooks/useTranslation'
9+
import { useAssetPath } from '../../utils/assetPath'
910

1011
function CityHero({ cityName, title, tagline, meetupName, credits }) {
1112
const { t } = useTranslation()
13+
const assetPath = useAssetPath()
1214
const [members, setMembers] = useState()
1315

1416
useEffect(() => {
@@ -30,7 +32,7 @@ function CityHero({ cityName, title, tagline, meetupName, credits }) {
3032
return (
3133
<div>
3234
<section>
33-
<div style={{ backgroundImage: `url(/${cityName}_cityBg.jpg)` }}>
35+
<div style={{ backgroundImage: `url(${assetPath(`/${cityName}_cityBg.jpg`)})` }}>
3436
<h1>{title}</h1>
3537
<p className='tagline'>
3638
<i>&quot;{tagline}&quot;</i>

components/Meta.tsx

Lines changed: 8 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,11 @@
11
import PropTypes from 'prop-types'
22
import Head from 'next/head'
33
import useTranslation from '../hooks/useTranslation'
4+
import { useAssetPath } from '../utils/assetPath'
45

56
export default function Meta({ pageTitle, pageDescription, pageImage }) {
67
const { t } = useTranslation()
8+
const assetPath = useAssetPath()
79
pageTitle = `${pageTitle} | OpenTechSchool`
810
return (
911
<>
@@ -22,30 +24,30 @@ export default function Meta({ pageTitle, pageDescription, pageImage }) {
2224
<meta
2325
property='og:image'
2426
content={`https://www.opentechschool.org${
25-
pageImage || '/sharing-images/website-into-sharing.png?1'
27+
pageImage || assetPath('/sharing-images/website-into-sharing.png?1')
2628
}`}
2729
/>
2830
<meta name='twitter:card' content='summary_large_image' />
2931
<meta name='twitter:site' content='@OpenTechSchool' />
3032
<link
3133
rel='apple-touch-icon'
3234
sizes='180x180'
33-
href='/apple-touch-icon.png'
35+
href={assetPath('/apple-touch-icon.png')}
3436
/>
35-
<link rel='shortcut icon' href='/favicon.ico' />
37+
<link rel='shortcut icon' href={assetPath('/favicon.ico')} />
3638
<link
3739
rel='icon'
3840
type='image/png'
39-
href='/favicon-32x32.png'
41+
href={assetPath('/favicon-32x32.png')}
4042
sizes='32x32'
4143
/>
4244
<link
4345
rel='icon'
4446
type='image/png'
45-
href='/favicon-96x96.png'
47+
href={assetPath('/favicon-96x96.png')}
4648
sizes='96x96'
4749
/>
48-
<link rel='manifest' href='/site.webmanifest' />
50+
<link rel='manifest' href={assetPath('/site.webmanifest')} />
4951
</Head>
5052
</>
5153
)

components/Team/MarkdownTeam.tsx

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
import PropTypes from 'prop-types'
22
import Grid from '@material-ui/core/Grid'
3+
import { useAssetPath } from '../../utils/assetPath'
34

45
function chunkArray(array, size) {
56
const chunkedArray = []
@@ -12,6 +13,7 @@ function chunkArray(array, size) {
1213
}
1314

1415
const TeamSection = ({ members }) => {
16+
const assetPath = useAssetPath()
1517
const chunksOfFour = chunkArray(members, 4)
1618

1719
return (
@@ -35,7 +37,7 @@ const TeamSection = ({ members }) => {
3537
key={key}
3638
item
3739
>
38-
<img src={`/members/${Object.keys(member)[0]}.jpg`} />
40+
<img src={assetPath(`/members/${Object.keys(member)[0]}.jpg`)} />
3941
<p className='name'>{Object.values(member)}</p>
4042
</Grid>
4143
)

containers/withLocale.tsx

Lines changed: 1 addition & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -8,30 +8,13 @@ interface LangProps {
88

99
const WithLocale = (WrappedPage: NextPage<any>) => {
1010
const WithLocale: NextPage<any, LangProps> = ({ ...pageProps }) => {
11-
// if (!locale) {
12-
// return <Error statusCode={404} />
13-
// }
14-
1511
return (
16-
<LocaleProvider lang={'en' /*locale*/}>
12+
<LocaleProvider lang={'en'}>
1713
<WrappedPage {...pageProps} />
1814
</LocaleProvider>
1915
)
2016
}
2117

22-
WithLocale.getInitialProps = async ctx => {
23-
let pageProps = {}
24-
if (WrappedPage.getInitialProps) {
25-
pageProps = await WrappedPage.getInitialProps(ctx)
26-
}
27-
28-
if (typeof ctx.query.lang !== 'string' || !isLocale(ctx.query.lang)) {
29-
return { ...pageProps, locale: undefined }
30-
}
31-
32-
return { ...pageProps, locale: ctx.query.lang }
33-
}
34-
3518
return WithLocale
3619
}
3720

0 commit comments

Comments
 (0)