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
105 changes: 64 additions & 41 deletions .github/workflows/deploy.yml
Original file line number Diff line number Diff line change
@@ -1,54 +1,77 @@
name: Deploy to Vercel
name: Deploy to CloudFlare

on:
push:
branches:
- '**'

permissions:
contents: write
jobs:
Build-and-Deploy:
env:
VERCEL_TOKEN: ${{ secrets.VERCEL_TOKEN }}
VERCEL_ORG_ID: ${{ secrets.VERCEL_ORG_ID }}
VERCEL_PROJECT_ID: ${{ secrets.VERCEL_PROJECT_ID }}
runs-on: ubuntu-latest
permissions:
contents: write
pull-requests: write
steps:
- uses: actions/checkout@v6
if: ${{ env.VERCEL_TOKEN && env.VERCEL_ORG_ID && env.VERCEL_PROJECT_ID }}
- uses: actions/checkout@v7

- name: Deploy to Vercel
id: vercel-deployment
if: ${{ env.VERCEL_TOKEN && env.VERCEL_ORG_ID && env.VERCEL_PROJECT_ID }}
uses: amondnet/vercel-action@v42.3.0
- uses: pnpm/action-setup@v6
with:
vercel-token: ${{ secrets.VERCEL_TOKEN }}
github-token: ${{ secrets.GITHUB_TOKEN }}
vercel-org-id: ${{ secrets.VERCEL_ORG_ID }}
vercel-project-id: ${{ secrets.VERCEL_PROJECT_ID }}
working-directory: ./
vercel-args: ${{ github.ref == 'refs/heads/main' && ' --prod' || '' }}

- name: Lark notification
uses: Open-Source-Bazaar/feishu-action@v3
version: 11

- uses: actions/setup-node@v7
with:
url: ${{ secrets.LARK_CHATBOT_HOOK_URL }}
msg_type: interactive
content: |
schema: "2.0"
config:
wide_screen_mode: true
header:
title:
tag: plain_text
content: Vercel deployment
template: blue
body:
elements:
- tag: markdown
content: |
- **Git Repository**: [${{ github.server_url }}/${{ github.repository }}](${{ github.server_url }}/${{ github.repository }})
- **Code Branch**: [${{ github.ref }}](${{ github.server_url }}/${{ github.repository }}/tree/${{ github.ref_name }})
- **Commit Author**: [${{ github.actor }}](${{ github.server_url }}/${{ github.actor }})
- **Preview Link**: [${{ steps.vercel-deployment.outputs.preview-url }}](${{ steps.vercel-deployment.outputs.preview-url }})
node-version: 24
registry-url: https://registry.npmjs.org
cache: pnpm

- name: Install Dependencies
run: pnpm i --frozen-lockfile

- name: Deploy to CloudFlare
env:
CLOUDFLARE_ACCOUNT_ID: ${{ secrets.CLOUDFLARE_ACCOUNT_ID }}
CLOUDFLARE_API_TOKEN: ${{ secrets.CLOUDFLARE_API_TOKEN }}
DEFAULT_BRANCH: ${{ github.event.repository.default_branch }}
GH_TOKEN: ${{ github.token }}
run: |
if [[ "$GITHUB_REF_NAME" == "$DEFAULT_BRANCH" ]]; then
echo "Deploying to production environment"
pnpm run deploy
else
BRANCH_SLUG=$(echo "$GITHUB_REF_NAME" | tr '[:upper:]' '[:lower:]' | sed -E 's/[^a-z0-9-]+/-/g; s/-+/-/g; s/^-+//; s/-+$//')
BRANCH_SLUG="${BRANCH_SLUG:0:40}"
PREVIEW_ALIAS="b-${BRANCH_SLUG}"
PREVIEW_SUMMARY_FILE="cloudflare-preview-summary.md"

echo "Building OpenNext bundle for preview URLs"
npx opennextjs-cloudflare build

echo "Uploading Worker version with preview alias: $PREVIEW_ALIAS"
npx wrangler versions upload \
--config wrangler.jsonc \
--preview-alias "$PREVIEW_ALIAS" \
--message "Preview for $GITHUB_REF_NAME @ $GITHUB_SHA" | \
tee wrangler-preview-output.log
{
echo "## Cloudflare Preview Deployment"
echo ""
echo "- Branch: $GITHUB_REF_NAME"
echo "- Commit: $GITHUB_SHA"
echo "- Preview Alias: $PREVIEW_ALIAS"
echo ""
echo "### Wrangler Output"
echo ''
grep -E 'workers.dev|preview|Version|Uploaded|Deployed' wrangler-preview-output.log || cat wrangler-preview-output.log
echo ''
} > "$PREVIEW_SUMMARY_FILE"

cat "$PREVIEW_SUMMARY_FILE" >> "$GITHUB_STEP_SUMMARY"

PR_NUMBER=$(gh pr list --head "$GITHUB_REF_NAME" --state open --json number --jq '.[0].number')
if [[ -n "$PR_NUMBER" ]]; then
echo "Posting preview summary to PR #$PR_NUMBER"
gh pr comment "$PR_NUMBER" --body-file "$PREVIEW_SUMMARY_FILE"
else
echo "No open PR found for branch $GITHUB_REF_NAME, skip PR comment"
fi
fi
5 changes: 5 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ yarn.lock
# next.js
/.next/
/out/
/.open-next/

# production
/build
Expand All @@ -39,6 +40,10 @@ yarn-error.log*
# vercel
.vercel

# CloudFlare
cloudflare-env.d.ts
.wrangler

# typescript
*.tsbuildinfo
next-env.d.ts
Expand Down
6 changes: 6 additions & 0 deletions app/globals.css
Original file line number Diff line number Diff line change
Expand Up @@ -132,3 +132,9 @@
@apply bg-background text-foreground;
}
}

/*
* ShadcnX CLI sets up the source rule for Tailwind CSS to include Git ignored components.
* Don't modify this rule if you are not a Tailwind CSS expert.
*/
@source "../components/ui/**/*.{js,jsx,ts,tsx,mdx,vue,svelte}";
2 changes: 2 additions & 0 deletions i18n/en-US.ts
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,8 @@ const BASE_TEXT = {
'calendar.saveDescription': 'iCalendar file',
'ui_text.search_placeholder': 'Search ...',
'ui_text.github_repo': 'GitHub Repo',
'mainnav.mobile.open': 'Open navigation menu',
'mainnav.mobile.close': 'Close navigation menu',
'home.selector.title': 'GoodAction Hub Home',
'home.selector.subtitle':
'Choose a module to enter: charity activity deadlines, accessible dining guide, or volunteer tutoring courses.',
Expand Down
17 changes: 8 additions & 9 deletions i18n/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,23 +13,22 @@ configure({ enforceActions: 'never' });

export type LanguageCode = 'zh-CN' | 'zh-TW' | 'en-US';

type TranslationData =
| TranslationMap<string>
| (() => Promise<{ default: TranslationMap<string> }>);
export type TranslationKey = keyof typeof zhCN;

type TranslationData<K extends string = string> =
TranslationMap<K> | (() => Promise<{ default: TranslationMap<K> }>);

const i18nData: Record<LanguageCode, TranslationData> = {
'zh-CN': zhCN,
'zh-TW': () => import('./zh-TW'),
'en-US': () => import('./en-US'),
};

type I18nTextKey = string;

export const createI18nStore = <N extends LanguageCode>(
export const createI18nStore = <N extends LanguageCode, K extends string>(
language?: N,
data?: TranslationMap<I18nTextKey>,
data?: TranslationMap<K>,
) => {
const store = new TranslationModel<LanguageCode, I18nTextKey>({
const store = new TranslationModel<N, K>({
...i18nData,
...(language && { [language]: data }),
});
Expand All @@ -40,7 +39,7 @@ export const createI18nStore = <N extends LanguageCode>(
return store;
};

export const i18n = createI18nStore();
export const i18n = createI18nStore<LanguageCode, TranslationKey>();

export const LanguageName: Record<LanguageCode, string> = {
'zh-CN': '简体中文',
Expand Down
2 changes: 2 additions & 0 deletions i18n/zh-CN.ts
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,8 @@ const BASE_TEXT = {
'calendar.saveDescription': 'iCalendar 文件',
'ui_text.search_placeholder': '搜索...',
'ui_text.github_repo': 'GitHub 仓库',
'mainnav.mobile.open': '打开导航菜单',
'mainnav.mobile.close': '关闭导航菜单',
'ui.language': '语言',
'metadata.description':
'追踪公益慈善会议、竞赛和活动重要截止日期的网站,帮助公益从业者、志愿者和爱心人士及时了解最新的公益慈善活动动态,不再错过参与公益事业、奉献爱心和社会服务的机会。',
Expand Down
2 changes: 2 additions & 0 deletions i18n/zh-TW.ts
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,8 @@ const BASE_TEXT = {
'calendar.saveDescription': 'iCalendar 檔案',
'ui_text.search_placeholder': '搜尋...',
'ui_text.github_repo': 'GitHub 倉庫',
'mainnav.mobile.open': '打開導覽選單',
'mainnav.mobile.close': '關閉導覽選單',
'ui.language': '語言',
'metadata.description':
'追蹤公益慈善會議、競賽和活動重要截止日期的網站,幫助公益從業者、志工和愛心人士及時了解最新的公益慈善活動動態,不再錯過參與公益事業、奉獻愛心和社會服務的機會。',
Expand Down
3 changes: 3 additions & 0 deletions open-next.config.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
import { defineCloudflareConfig } from '@opennextjs/cloudflare';

export default defineCloudflareConfig();
66 changes: 35 additions & 31 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,9 @@
"dev": "next dev",
"build": "next build",
"start": "next start",
"preview": "opennextjs-cloudflare build && opennextjs-cloudflare preview",
"deploy": "opennextjs-cloudflare build && opennextjs-cloudflare deploy",
"cf-typegen": "wrangler types --env-interface CloudflareEnv cloudflare-env.d.ts",
"test": "next typegen && lint-staged && git add . && tsc --noEmit",
"knip": "knip",
"prepare": "husky"
Expand All @@ -20,54 +23,55 @@
},
"dependencies": {
"@giscus/react": "^3.1.0",
"@radix-ui/react-dialog": "^1.1.16",
"@radix-ui/react-dropdown-menu": "^2.1.17",
"@opennextjs/cloudflare": "^1.20.2",
"@radix-ui/react-dialog": "^1.1.23",
"@radix-ui/react-dropdown-menu": "^2.1.24",
"@radix-ui/react-icons": "^1.3.2",
"@radix-ui/react-label": "^2.1.9",
"@radix-ui/react-scroll-area": "^1.2.11",
"@radix-ui/react-select": "^2.3.0",
"@radix-ui/react-slot": "^1.2.5",
"@radix-ui/react-switch": "^1.3.0",
"@radix-ui/react-label": "^2.1.15",
"@radix-ui/react-scroll-area": "^1.2.18",
"@radix-ui/react-select": "^2.3.7",
"@radix-ui/react-slot": "^1.3.3",
"@radix-ui/react-switch": "^1.3.7",
"browser-fs-access": "^0.38.0",
"calendar-link": "^2.11.3",
"calendar-link": "^2.11.4",
"class-variance-authority": "^0.7.1",
"clsx": "^2.1.1",
"fuse.js": "^7.4.2",
"lucide-react": "^1.17.0",
"fuse.js": "^7.5.0",
"lucide-react": "^1.28.0",
"luxon": "^3.7.2",
"mobx": "^6.16.0",
"mobx-i18n": "^0.7.2",
"mobx": "^6.16.1",
"mobx-i18n": "^0.7.5",
"mobx-react": "^9.2.2",
"mobx-restful": "^2.1.4",
"next": "^16.2.7",
"next": "^16.3.0",
"open-react-map": "^0.9.1",
"radix-ui": "^1.5.0",
"react": "^19.2.7",
"react-dom": "^19.2.7",
"radix-ui": "^1.6.7",
"react": "^19.2.8",
"react-dom": "^19.2.8",
"react-markdown": "^9.1.0",
"remark-gfm": "^4.0.1",
"tailwind-merge": "^3.6.0",
"web-utility": "^4.6.6",
"ws": "^8.21.0",
"web-utility": "^4.7.2",
"ws": "^8.21.2",
"zustand": "^5.0.14"
},
"devDependencies": {
"@tailwindcss/postcss": "^4.3.0",
"@types/luxon": "^3.7.1",
"@types/node": "^24.13.1",
"@types/react": "^19.2.17",
"@types/react-dom": "^19.2.3",
"@tailwindcss/postcss": "^4.3.3",
"@types/luxon": "^3.7.3",
"@types/node": "^24.13.3",
"@types/react": "^19.2.18",
"@types/react-dom": "^19.2.4",
"@types/ws": "^8.18.1",
"eslint": "^10.4.1",
"eslint-config-next": "^16.2.7",
"eslint": "^10.8.0",
"eslint-config-next": "^16.3.0",
"husky": "^9.1.7",
"jiti": "^2.7.0",
"knip": "^5.88.1",
"lint-staged": "^17.0.7",
"prettier": "^3.8.3",
"tailwindcss": "^4.3.0",
"lint-staged": "^17.3.0",
"prettier": "^3.9.6",
"tailwindcss": "^4.3.3",
"tw-animate-css": "^1.4.0",
"typescript": "^5.9.3"
},
"packageManager": "pnpm@11.5.2"
"typescript": "^5.9.3",
"wrangler": "^4.118.0"
}
}
Loading