Fix light mode visibility and sermon page filtering

- Implement dual theme system with separate Tailwind configs for light/dark modes
- Add dynamic stylesheet switching based on system preference
- Fix light mode text visibility by using darker colors on light backgrounds
- Resolve sermon page bug where all content loaded on initial render
- Add build scripts for theme compilation
- Update recurring event type formatting consistency
This commit is contained in:
Benjamin Slingo 2025-08-23 14:27:42 -04:00
parent b700c45b06
commit b1796b0475
17 changed files with 987 additions and 148 deletions

24
astro-church-website/.gitignore vendored Normal file
View file

@ -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/

View file

@ -0,0 +1,124 @@
# Deployment Instructions
## Files to Copy to Server
### New/Modified Files:
```
src/pages/admin/index.astro # Main admin dashboard page
src/components/admin/Login.astro # Admin login component
src/pages/bulletin/[id].astro # Fixed bulletin detail page (SSR)
public/admin/scripts/main.js # Admin JavaScript (if not already there)
```
### Verify these files exist on server:
```
public/admin/scripts/main.js # Admin functionality
```
## Deployment Steps
1. **Copy files to server:**
```bash
# Copy new admin components
scp -r src/pages/admin/ user@server:/opt/rtsda/src/pages/
scp -r src/components/admin/ user@server:/opt/rtsda/src/components/
# Copy fixed bulletin page
scp src/pages/bulletin/[id].astro user@server:/opt/rtsda/src/pages/bulletin/
# Verify admin scripts exist
scp public/admin/scripts/main.js user@server:/opt/rtsda/public/admin/scripts/
```
2. **SSH into server:**
```bash
ssh user@server
cd /opt/rtsda
```
3. **Build and restart:**
```bash
npm run build
pm2 restart astro-app
```
## Testing After Deployment
1. **Test bulletin fix:**
- Visit: `https://yourdomain.com/bulletin/5bebfe94-71ca-4a72-b9a8-ecd1195c8182`
- Should show bulletin content, not "bulletin not found"
2. **Test admin dashboard:**
- Visit: `https://yourdomain.com/admin/`
- Should show login screen
- Login with admin credentials
- Verify all sections work: Events, Bulletins, Schedules
## Potential Issues & Solutions
### Build Errors:
```bash
# If node version issues:
node --version # Should be 20.x
npm --version
# If dependency issues:
rm -rf node_modules package-lock.json
npm install
npm run build
```
### Permission Issues:
```bash
# Fix ownership
sudo chown -R $USER:$USER /opt/rtsda
chmod -R 755 /opt/rtsda
# Fix specific file permissions
chmod 644 src/pages/admin/index.astro
chmod 644 src/components/admin/Login.astro
chmod 644 src/pages/bulletin/[id].astro
```
### Admin Route Not Working:
- Check if `/admin/` route is accessible
- Verify admin files were copied correctly
- Check PM2 logs: `pm2 logs astro-app`
### Styles Not Loading:
- Hard refresh browser (Ctrl+F5)
- Check if build completed successfully
- Verify no CSS compilation errors in build output
## Rollback Plan
If something breaks:
```bash
# Quick rollback
git status
git checkout -- src/pages/bulletin/[id].astro
rm -rf src/pages/admin/
rm -rf src/components/admin/
npm run build
pm2 restart astro-app
```
## Success Indicators
✅ Build completes without errors
✅ Bulletin pages show content instead of "not found"
`/admin/` shows login screen
✅ Admin dashboard fully functional after login
✅ Site loads normally for regular visitors
## Notes
- Admin dashboard is completely hidden from public navigation
- Only accessible via direct URL: `/admin/`
- Requires valid JWT authentication
- All original functionality preserved
- Styling matches main site theme
---
*"It should be simple, but it probably won't be." - Murphy's Law of Deployment*

View file

@ -0,0 +1,29 @@
FROM node:20-bullseye
# Install Rust
RUN curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh -s -- -y
ENV PATH="/root/.cargo/bin:${PATH}"
# Set working directory
WORKDIR /app
# Copy the church-core dependency first
COPY church-core /church-core
# Copy package files
COPY astro-church-website/package*.json ./
# Install Node dependencies
RUN npm install
# Copy source code
COPY astro-church-website .
# Build native bindings and Astro site
RUN npm run build
# Create output directory
RUN mkdir -p /output && \
cp -r dist/ /output/ && \
cp *.node /output/ && \
cp package.json index.* *.cjs *.mjs /output/ 2>/dev/null || true

View file

@ -0,0 +1,43 @@
# Astro Starter Kit: Minimal
```sh
npm 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 |
| :------------------------ | :----------------------------------------------- |
| `npm install` | Installs dependencies |
| `npm run dev` | Starts local dev server at `localhost:4321` |
| `npm run build` | Build your production site to `./dist/` |
| `npm run preview` | Preview your build locally, before deploying |
| `npm run astro ...` | Run CLI commands like `astro add`, `astro check` |
| `npm run 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).

View file

@ -11,6 +11,8 @@
"@astrojs/node": "^9.4.2", "@astrojs/node": "^9.4.2",
"@astrojs/tailwind": "^6.0.2", "@astrojs/tailwind": "^6.0.2",
"astro": "^5.13.0", "astro": "^5.13.0",
"form-data": "^4.0.4",
"node-fetch": "^3.3.2",
"tailwindcss": "^3.4.17" "tailwindcss": "^3.4.17"
}, },
"devDependencies": { "devDependencies": {
@ -1814,6 +1816,12 @@
"sharp": "^0.33.3" "sharp": "^0.33.3"
} }
}, },
"node_modules/asynckit": {
"version": "0.4.0",
"resolved": "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz",
"integrity": "sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q==",
"license": "MIT"
},
"node_modules/autoprefixer": { "node_modules/autoprefixer": {
"version": "10.4.21", "version": "10.4.21",
"resolved": "https://registry.npmjs.org/autoprefixer/-/autoprefixer-10.4.21.tgz", "resolved": "https://registry.npmjs.org/autoprefixer/-/autoprefixer-10.4.21.tgz",
@ -2018,6 +2026,19 @@
"node": "^6 || ^7 || ^8 || ^9 || ^10 || ^11 || ^12 || >=13.7" "node": "^6 || ^7 || ^8 || ^9 || ^10 || ^11 || ^12 || >=13.7"
} }
}, },
"node_modules/call-bind-apply-helpers": {
"version": "1.0.2",
"resolved": "https://registry.npmjs.org/call-bind-apply-helpers/-/call-bind-apply-helpers-1.0.2.tgz",
"integrity": "sha512-Sp1ablJ0ivDkSzjcaJdxEunN5/XvksFJ2sMBFfq6x0ryhQV/2b/KwFe21cMpmHtPOSij8K99/wSfoEuTObmuMQ==",
"license": "MIT",
"dependencies": {
"es-errors": "^1.3.0",
"function-bind": "^1.1.2"
},
"engines": {
"node": ">= 0.4"
}
},
"node_modules/camelcase": { "node_modules/camelcase": {
"version": "8.0.0", "version": "8.0.0",
"resolved": "https://registry.npmjs.org/camelcase/-/camelcase-8.0.0.tgz", "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-8.0.0.tgz",
@ -2214,6 +2235,18 @@
"simple-swizzle": "^0.2.2" "simple-swizzle": "^0.2.2"
} }
}, },
"node_modules/combined-stream": {
"version": "1.0.8",
"resolved": "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.8.tgz",
"integrity": "sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg==",
"license": "MIT",
"dependencies": {
"delayed-stream": "~1.0.0"
},
"engines": {
"node": ">= 0.8"
}
},
"node_modules/comma-separated-tokens": { "node_modules/comma-separated-tokens": {
"version": "2.0.3", "version": "2.0.3",
"resolved": "https://registry.npmjs.org/comma-separated-tokens/-/comma-separated-tokens-2.0.3.tgz", "resolved": "https://registry.npmjs.org/comma-separated-tokens/-/comma-separated-tokens-2.0.3.tgz",
@ -2263,6 +2296,26 @@
"node-fetch": "^2.7.0" "node-fetch": "^2.7.0"
} }
}, },
"node_modules/cross-fetch/node_modules/node-fetch": {
"version": "2.7.0",
"resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-2.7.0.tgz",
"integrity": "sha512-c4FRfUm/dbcWZ7U+1Wq0AwCyFL+3nt2bEw05wfxSz+DWpWsitgmSgYmy2dQdWyKC1694ELPqMs/YzUSNozLt8A==",
"license": "MIT",
"dependencies": {
"whatwg-url": "^5.0.0"
},
"engines": {
"node": "4.x || >=6.0.0"
},
"peerDependencies": {
"encoding": "^0.1.0"
},
"peerDependenciesMeta": {
"encoding": {
"optional": true
}
}
},
"node_modules/cross-spawn": { "node_modules/cross-spawn": {
"version": "7.0.6", "version": "7.0.6",
"resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.6.tgz", "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.6.tgz",
@ -2311,6 +2364,15 @@
"node": ">=4" "node": ">=4"
} }
}, },
"node_modules/data-uri-to-buffer": {
"version": "4.0.1",
"resolved": "https://registry.npmjs.org/data-uri-to-buffer/-/data-uri-to-buffer-4.0.1.tgz",
"integrity": "sha512-0R9ikRb668HB7QDxT1vkpuUBtqc53YyAwMwGeUFKRojY/NWKvdZ+9UYtRfGmhqNbRkTSVpMbmyhXipFFv2cb/A==",
"license": "MIT",
"engines": {
"node": ">= 12"
}
},
"node_modules/debug": { "node_modules/debug": {
"version": "4.4.1", "version": "4.4.1",
"resolved": "https://registry.npmjs.org/debug/-/debug-4.4.1.tgz", "resolved": "https://registry.npmjs.org/debug/-/debug-4.4.1.tgz",
@ -2347,6 +2409,15 @@
"integrity": "sha512-mEQCMmwJu317oSz8CwdIOdwf3xMif1ttiM8LTufzc3g6kR+9Pe236twL8j3IYT1F7GfRgGcW6MWxzZjLIkuHIg==", "integrity": "sha512-mEQCMmwJu317oSz8CwdIOdwf3xMif1ttiM8LTufzc3g6kR+9Pe236twL8j3IYT1F7GfRgGcW6MWxzZjLIkuHIg==",
"license": "MIT" "license": "MIT"
}, },
"node_modules/delayed-stream": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz",
"integrity": "sha512-ZySD7Nf91aLB0RxL4KGrKHBXl7Eds1DAmEdcoVawXnLD7SDhpNgtuII2aAkg7a7QS41jxPSZ17p4VdGnMHk3MQ==",
"license": "MIT",
"engines": {
"node": ">=0.4.0"
}
},
"node_modules/depd": { "node_modules/depd": {
"version": "2.0.0", "version": "2.0.0",
"resolved": "https://registry.npmjs.org/depd/-/depd-2.0.0.tgz", "resolved": "https://registry.npmjs.org/depd/-/depd-2.0.0.tgz",
@ -2448,6 +2519,20 @@
"node": ">=4" "node": ">=4"
} }
}, },
"node_modules/dunder-proto": {
"version": "1.0.1",
"resolved": "https://registry.npmjs.org/dunder-proto/-/dunder-proto-1.0.1.tgz",
"integrity": "sha512-KIN/nDJBQRcXw0MLVhZE9iQHmG68qAVIBg9CqmUYjmQIhgij9U5MFvrqkUL5FbtyyzZuOeOt0zdeRe4UY7ct+A==",
"license": "MIT",
"dependencies": {
"call-bind-apply-helpers": "^1.0.1",
"es-errors": "^1.3.0",
"gopd": "^1.2.0"
},
"engines": {
"node": ">= 0.4"
}
},
"node_modules/eastasianwidth": { "node_modules/eastasianwidth": {
"version": "0.2.0", "version": "0.2.0",
"resolved": "https://registry.npmjs.org/eastasianwidth/-/eastasianwidth-0.2.0.tgz", "resolved": "https://registry.npmjs.org/eastasianwidth/-/eastasianwidth-0.2.0.tgz",
@ -2493,12 +2578,57 @@
"url": "https://github.com/fb55/entities?sponsor=1" "url": "https://github.com/fb55/entities?sponsor=1"
} }
}, },
"node_modules/es-define-property": {
"version": "1.0.1",
"resolved": "https://registry.npmjs.org/es-define-property/-/es-define-property-1.0.1.tgz",
"integrity": "sha512-e3nRfgfUZ4rNGL232gUgX06QNyyez04KdjFrF+LTRoOXmrOgFKDg4BCdsjW8EnT69eqdYGmRpJwiPVYNrCaW3g==",
"license": "MIT",
"engines": {
"node": ">= 0.4"
}
},
"node_modules/es-errors": {
"version": "1.3.0",
"resolved": "https://registry.npmjs.org/es-errors/-/es-errors-1.3.0.tgz",
"integrity": "sha512-Zf5H2Kxt2xjTvbJvP2ZWLEICxA6j+hAmMzIlypy4xcBg1vKVnx89Wy0GbS+kf5cwCVFFzdCFh2XSCFNULS6csw==",
"license": "MIT",
"engines": {
"node": ">= 0.4"
}
},
"node_modules/es-module-lexer": { "node_modules/es-module-lexer": {
"version": "1.7.0", "version": "1.7.0",
"resolved": "https://registry.npmjs.org/es-module-lexer/-/es-module-lexer-1.7.0.tgz", "resolved": "https://registry.npmjs.org/es-module-lexer/-/es-module-lexer-1.7.0.tgz",
"integrity": "sha512-jEQoCwk8hyb2AZziIOLhDqpm5+2ww5uIE6lkO/6jcOCusfk6LhMHpXXfBLXTZ7Ydyt0j4VoUQv6uGNYbdW+kBA==", "integrity": "sha512-jEQoCwk8hyb2AZziIOLhDqpm5+2ww5uIE6lkO/6jcOCusfk6LhMHpXXfBLXTZ7Ydyt0j4VoUQv6uGNYbdW+kBA==",
"license": "MIT" "license": "MIT"
}, },
"node_modules/es-object-atoms": {
"version": "1.1.1",
"resolved": "https://registry.npmjs.org/es-object-atoms/-/es-object-atoms-1.1.1.tgz",
"integrity": "sha512-FGgH2h8zKNim9ljj7dankFPcICIK9Cp5bm+c2gQSYePhpaG5+esrLODihIorn+Pe6FGJzWhXQotPv73jTaldXA==",
"license": "MIT",
"dependencies": {
"es-errors": "^1.3.0"
},
"engines": {
"node": ">= 0.4"
}
},
"node_modules/es-set-tostringtag": {
"version": "2.1.0",
"resolved": "https://registry.npmjs.org/es-set-tostringtag/-/es-set-tostringtag-2.1.0.tgz",
"integrity": "sha512-j6vWzfrGVfyXxge+O0x5sh6cvxAog0a/4Rdd2K36zCMV5eJ+/+tOAngRO8cODMNWbVRdVlmGZQL2YS3yR8bIUA==",
"license": "MIT",
"dependencies": {
"es-errors": "^1.3.0",
"get-intrinsic": "^1.2.6",
"has-tostringtag": "^1.0.2",
"hasown": "^2.0.2"
},
"engines": {
"node": ">= 0.4"
}
},
"node_modules/esbuild": { "node_modules/esbuild": {
"version": "0.25.9", "version": "0.25.9",
"resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.25.9.tgz", "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.25.9.tgz",
@ -2657,6 +2787,29 @@
} }
} }
}, },
"node_modules/fetch-blob": {
"version": "3.2.0",
"resolved": "https://registry.npmjs.org/fetch-blob/-/fetch-blob-3.2.0.tgz",
"integrity": "sha512-7yAQpD2UMJzLi1Dqv7qFYnPbaPx7ZfFK6PiIxQ4PfkGPyNyl2Ugx+a/umUonmKqjhM4DnfbMvdX6otXq83soQQ==",
"funding": [
{
"type": "github",
"url": "https://github.com/sponsors/jimmywarting"
},
{
"type": "paypal",
"url": "https://paypal.me/jimmywarting"
}
],
"license": "MIT",
"dependencies": {
"node-domexception": "^1.0.0",
"web-streams-polyfill": "^3.0.3"
},
"engines": {
"node": "^12.20 || >= 14.13"
}
},
"node_modules/fill-range": { "node_modules/fill-range": {
"version": "7.1.1", "version": "7.1.1",
"resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.1.1.tgz", "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.1.1.tgz",
@ -2721,6 +2874,55 @@
"url": "https://github.com/sponsors/isaacs" "url": "https://github.com/sponsors/isaacs"
} }
}, },
"node_modules/form-data": {
"version": "4.0.4",
"resolved": "https://registry.npmjs.org/form-data/-/form-data-4.0.4.tgz",
"integrity": "sha512-KrGhL9Q4zjj0kiUt5OO4Mr/A/jlI2jDYs5eHBpYHPcBEVSiipAvn2Ko2HnPe20rmcuuvMHNdZFp+4IlGTMF0Ow==",
"license": "MIT",
"dependencies": {
"asynckit": "^0.4.0",
"combined-stream": "^1.0.8",
"es-set-tostringtag": "^2.1.0",
"hasown": "^2.0.2",
"mime-types": "^2.1.12"
},
"engines": {
"node": ">= 6"
}
},
"node_modules/form-data/node_modules/mime-db": {
"version": "1.52.0",
"resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.52.0.tgz",
"integrity": "sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==",
"license": "MIT",
"engines": {
"node": ">= 0.6"
}
},
"node_modules/form-data/node_modules/mime-types": {
"version": "2.1.35",
"resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.35.tgz",
"integrity": "sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==",
"license": "MIT",
"dependencies": {
"mime-db": "1.52.0"
},
"engines": {
"node": ">= 0.6"
}
},
"node_modules/formdata-polyfill": {
"version": "4.0.10",
"resolved": "https://registry.npmjs.org/formdata-polyfill/-/formdata-polyfill-4.0.10.tgz",
"integrity": "sha512-buewHzMvYL29jdeQTVILecSaZKnt/RJWjoZCF5OW60Z67/GmSLBkOFM7qh1PI3zFNtJbaZL5eQu1vLfazOwj4g==",
"license": "MIT",
"dependencies": {
"fetch-blob": "^3.1.2"
},
"engines": {
"node": ">=12.20.0"
}
},
"node_modules/fraction.js": { "node_modules/fraction.js": {
"version": "4.3.7", "version": "4.3.7",
"resolved": "https://registry.npmjs.org/fraction.js/-/fraction.js-4.3.7.tgz", "resolved": "https://registry.npmjs.org/fraction.js/-/fraction.js-4.3.7.tgz",
@ -2778,6 +2980,43 @@
"url": "https://github.com/sponsors/sindresorhus" "url": "https://github.com/sponsors/sindresorhus"
} }
}, },
"node_modules/get-intrinsic": {
"version": "1.3.0",
"resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.3.0.tgz",
"integrity": "sha512-9fSjSaos/fRIVIp+xSJlE6lfwhES7LNtKaCBIamHsjr2na1BiABJPo0mOjjz8GJDURarmCPGqaiVg5mfjb98CQ==",
"license": "MIT",
"dependencies": {
"call-bind-apply-helpers": "^1.0.2",
"es-define-property": "^1.0.1",
"es-errors": "^1.3.0",
"es-object-atoms": "^1.1.1",
"function-bind": "^1.1.2",
"get-proto": "^1.0.1",
"gopd": "^1.2.0",
"has-symbols": "^1.1.0",
"hasown": "^2.0.2",
"math-intrinsics": "^1.1.0"
},
"engines": {
"node": ">= 0.4"
},
"funding": {
"url": "https://github.com/sponsors/ljharb"
}
},
"node_modules/get-proto": {
"version": "1.0.1",
"resolved": "https://registry.npmjs.org/get-proto/-/get-proto-1.0.1.tgz",
"integrity": "sha512-sTSfBjoXBp89JvIKIefqw7U2CCebsc74kiY6awiGogKtoSGbgjYE/G/+l9sF3MWFPNc9IcoOC4ODfKHfxFmp0g==",
"license": "MIT",
"dependencies": {
"dunder-proto": "^1.0.1",
"es-object-atoms": "^1.0.0"
},
"engines": {
"node": ">= 0.4"
}
},
"node_modules/github-slugger": { "node_modules/github-slugger": {
"version": "2.0.0", "version": "2.0.0",
"resolved": "https://registry.npmjs.org/github-slugger/-/github-slugger-2.0.0.tgz", "resolved": "https://registry.npmjs.org/github-slugger/-/github-slugger-2.0.0.tgz",
@ -2816,6 +3055,18 @@
"node": ">=10.13.0" "node": ">=10.13.0"
} }
}, },
"node_modules/gopd": {
"version": "1.2.0",
"resolved": "https://registry.npmjs.org/gopd/-/gopd-1.2.0.tgz",
"integrity": "sha512-ZUKRh6/kUFoAiTAtTYPZJ3hw9wNxx+BIBOijnlG9PnrJsCcSjs1wyyD6vJpaYtgnzDrKYRSqf3OO6Rfa93xsRg==",
"license": "MIT",
"engines": {
"node": ">= 0.4"
},
"funding": {
"url": "https://github.com/sponsors/ljharb"
}
},
"node_modules/h3": { "node_modules/h3": {
"version": "1.15.4", "version": "1.15.4",
"resolved": "https://registry.npmjs.org/h3/-/h3-1.15.4.tgz", "resolved": "https://registry.npmjs.org/h3/-/h3-1.15.4.tgz",
@ -2833,6 +3084,33 @@
"uncrypto": "^0.1.3" "uncrypto": "^0.1.3"
} }
}, },
"node_modules/has-symbols": {
"version": "1.1.0",
"resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.1.0.tgz",
"integrity": "sha512-1cDNdwJ2Jaohmb3sg4OmKaMBwuC48sYni5HUw2DvsC8LjGTLK9h+eb1X6RyuOHe4hT0ULCW68iomhjUoKUqlPQ==",
"license": "MIT",
"engines": {
"node": ">= 0.4"
},
"funding": {
"url": "https://github.com/sponsors/ljharb"
}
},
"node_modules/has-tostringtag": {
"version": "1.0.2",
"resolved": "https://registry.npmjs.org/has-tostringtag/-/has-tostringtag-1.0.2.tgz",
"integrity": "sha512-NqADB8VjPFLM2V0VvHUewwwsw0ZWBaIdgo+ieHtK3hasLz4qeCRjYcqfB6AQrBggRKppKF8L52/VqdVsO47Dlw==",
"license": "MIT",
"dependencies": {
"has-symbols": "^1.0.3"
},
"engines": {
"node": ">= 0.4"
},
"funding": {
"url": "https://github.com/sponsors/ljharb"
}
},
"node_modules/hasown": { "node_modules/hasown": {
"version": "2.0.2", "version": "2.0.2",
"resolved": "https://registry.npmjs.org/hasown/-/hasown-2.0.2.tgz", "resolved": "https://registry.npmjs.org/hasown/-/hasown-2.0.2.tgz",
@ -3352,6 +3630,15 @@
"url": "https://github.com/sponsors/wooorm" "url": "https://github.com/sponsors/wooorm"
} }
}, },
"node_modules/math-intrinsics": {
"version": "1.1.0",
"resolved": "https://registry.npmjs.org/math-intrinsics/-/math-intrinsics-1.1.0.tgz",
"integrity": "sha512-/IXtbwEk5HTPyEwyKX6hGkYXxM9nbj64B+ilVJnC/R6B0pH5G4V3b0pVbL7DBj4tkhBAppbQUlf6F6Xl9LHu1g==",
"license": "MIT",
"engines": {
"node": ">= 0.4"
}
},
"node_modules/mdast-util-definitions": { "node_modules/mdast-util-definitions": {
"version": "6.0.0", "version": "6.0.0",
"resolved": "https://registry.npmjs.org/mdast-util-definitions/-/mdast-util-definitions-6.0.0.tgz", "resolved": "https://registry.npmjs.org/mdast-util-definitions/-/mdast-util-definitions-6.0.0.tgz",
@ -4291,24 +4578,42 @@
"url": "https://opencollective.com/unified" "url": "https://opencollective.com/unified"
} }
}, },
"node_modules/node-domexception": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/node-domexception/-/node-domexception-1.0.0.tgz",
"integrity": "sha512-/jKZoMpw0F8GRwl4/eLROPA3cfcXtLApP0QzLmUT/HuPCZWyB7IY9ZrMeKw2O/nFIqPQB3PVM9aYm0F312AXDQ==",
"deprecated": "Use your platform's native DOMException instead",
"funding": [
{
"type": "github",
"url": "https://github.com/sponsors/jimmywarting"
},
{
"type": "github",
"url": "https://paypal.me/jimmywarting"
}
],
"license": "MIT",
"engines": {
"node": ">=10.5.0"
}
},
"node_modules/node-fetch": { "node_modules/node-fetch": {
"version": "2.7.0", "version": "3.3.2",
"resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-2.7.0.tgz", "resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-3.3.2.tgz",
"integrity": "sha512-c4FRfUm/dbcWZ7U+1Wq0AwCyFL+3nt2bEw05wfxSz+DWpWsitgmSgYmy2dQdWyKC1694ELPqMs/YzUSNozLt8A==", "integrity": "sha512-dRB78srN/l6gqWulah9SrxeYnxeddIG30+GOqK/9OlLVyLg3HPnr6SqOWTWOXKRwC2eGYCkZ59NNuSgvSrpgOA==",
"license": "MIT", "license": "MIT",
"dependencies": { "dependencies": {
"whatwg-url": "^5.0.0" "data-uri-to-buffer": "^4.0.0",
"fetch-blob": "^3.1.4",
"formdata-polyfill": "^4.0.10"
}, },
"engines": { "engines": {
"node": "4.x || >=6.0.0" "node": "^12.20.0 || ^14.13.1 || >=16.0.0"
}, },
"peerDependencies": { "funding": {
"encoding": "^0.1.0" "type": "opencollective",
}, "url": "https://opencollective.com/node-fetch"
"peerDependenciesMeta": {
"encoding": {
"optional": true
}
} }
}, },
"node_modules/node-fetch-native": { "node_modules/node-fetch-native": {
@ -6191,6 +6496,15 @@
"url": "https://github.com/sponsors/wooorm" "url": "https://github.com/sponsors/wooorm"
} }
}, },
"node_modules/web-streams-polyfill": {
"version": "3.3.3",
"resolved": "https://registry.npmjs.org/web-streams-polyfill/-/web-streams-polyfill-3.3.3.tgz",
"integrity": "sha512-d2JWLCivmZYTSIoge9MsgFCZrt571BikcWGYkjC1khllbTeDlGqZ2D8vD8E/lJa8WGWbb7Plm8/XJYV7IJHZZw==",
"license": "MIT",
"engines": {
"node": ">= 8"
}
},
"node_modules/webidl-conversions": { "node_modules/webidl-conversions": {
"version": "3.0.1", "version": "3.0.1",
"resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-3.0.1.tgz", "resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-3.0.1.tgz",

View file

@ -4,8 +4,11 @@
"version": "0.0.1", "version": "0.0.1",
"scripts": { "scripts": {
"dev": "astro dev", "dev": "astro dev",
"build": "npm run build:native && astro build", "build": "npm run build:native && npm run build:themes && astro build",
"build:native": "napi build --platform --release", "build:native": "napi build --platform --release",
"build:themes": "npm run build:theme-light && npm run build:theme-dark",
"build:theme-light": "tailwindcss -c tailwind.light.config.mjs -i ./src/styles/theme-input.css -o ./public/css/theme-light.css --minify",
"build:theme-dark": "tailwindcss -c tailwind.dark.config.mjs -i ./src/styles/theme-input.css -o ./public/css/theme-dark.css --minify",
"preview": "astro preview", "preview": "astro preview",
"astro": "astro" "astro": "astro"
}, },
@ -13,6 +16,8 @@
"@astrojs/node": "^9.4.2", "@astrojs/node": "^9.4.2",
"@astrojs/tailwind": "^6.0.2", "@astrojs/tailwind": "^6.0.2",
"astro": "^5.13.0", "astro": "^5.13.0",
"form-data": "^4.0.4",
"node-fetch": "^3.3.2",
"tailwindcss": "^3.4.17" "tailwindcss": "^3.4.17"
}, },
"devDependencies": { "devDependencies": {

View file

@ -106,7 +106,7 @@ function formatRecurringTypeLabel(type) {
case 'biweekly': return 'Every Two Weeks'; case 'biweekly': return 'Every Two Weeks';
case 'monthly': return 'Monthly'; case 'monthly': return 'Monthly';
case 'first_tuesday': return 'First Tuesday of Month'; case 'first_tuesday': return 'First Tuesday of Month';
case '2nd/3rd Saturday Monthly': return '2nd/3rd Saturday Monthly'; case '2nd_3rd_saturday_monthly': return '2nd/3rd Saturday Monthly';
default: default:
// Capitalize first letter of each word // Capitalize first letter of each word
return type.split('_').map(word => word.charAt(0).toUpperCase() + word.slice(1)).join(' '); return type.split('_').map(word => word.charAt(0).toUpperCase() + word.slice(1)).join(' ');

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View file

@ -24,127 +24,32 @@ const { title, description = 'Proclaiming the Three Angels\' Message with love a
<!-- Lucide Icons --> <!-- Lucide Icons -->
<script src="https://unpkg.com/lucide@latest/dist/umd/lucide.js"></script> <script src="https://unpkg.com/lucide@latest/dist/umd/lucide.js"></script>
<!-- Custom Styles for modern design --> <!-- Dynamic Theme CSS -->
<style> <link id="theme-stylesheet" rel="stylesheet" href="/css/theme-light.css">
/* Custom scrollbar for webkit browsers */
::-webkit-scrollbar { <!-- Theme Detection Script - Must run immediately -->
width: 6px; <script is:inline>
} (function() {
::-webkit-scrollbar-track { function setTheme() {
background: #f1f5f9; const prefersDark = window.matchMedia('(prefers-color-scheme: dark)').matches;
} const themeStylesheet = document.getElementById('theme-stylesheet');
::-webkit-scrollbar-thumb {
background: #6366f1; if (prefersDark) {
border-radius: 3px; themeStylesheet.href = '/css/theme-dark.css';
} document.documentElement.classList.add('dark');
::-webkit-scrollbar-thumb:hover { } else {
background: #4f46e5; themeStylesheet.href = '/css/theme-light.css';
} document.documentElement.classList.remove('dark');
}
/* Smooth animations */
* {
transition: all 0.2s ease-in-out;
}
/* Focus states for accessibility */
:focus-visible {
outline: 2px solid #6366f1;
outline-offset: 2px;
}
/* Custom gradient backgrounds */
.bg-divine-gradient {
background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
}
.bg-heavenly-gradient {
background: linear-gradient(135deg, #6366f1 0%, #8b5cf6 50%, #a855f7 100%);
}
.bg-sacred-gradient {
background: linear-gradient(135deg, #f59e0b 0%, #d97706 100%);
}
/* Text gradient utilities */
.text-divine-gradient {
background: linear-gradient(135deg, #6366f1 0%, #8b5cf6 100%);
-webkit-background-clip: text;
-webkit-text-fill-color: transparent;
background-clip: text;
}
.text-golden-gradient {
background: linear-gradient(135deg, #f59e0b 0%, #d97706 100%);
-webkit-background-clip: text;
-webkit-text-fill-color: transparent;
background-clip: text;
}
/* Dark mode support */
@media (prefers-color-scheme: dark) {
::-webkit-scrollbar-track {
background: #1e293b;
} }
}
// Set initial theme
/* Modern glass morphism effects */ setTheme();
.glass {
background: rgba(255, 255, 255, 0.25); // Listen for system theme changes
backdrop-filter: blur(10px); window.matchMedia('(prefers-color-scheme: dark)').addEventListener('change', setTheme);
border: 1px solid rgba(255, 255, 255, 0.18); })();
} </script>
.glass-dark {
background: rgba(0, 0, 0, 0.25);
backdrop-filter: blur(10px);
border: 1px solid rgba(255, 255, 255, 0.1);
}
/* Custom animations */
@keyframes fadeInUp {
from {
opacity: 0;
transform: translateY(30px);
}
to {
opacity: 1;
transform: translateY(0);
}
}
@keyframes float {
0%, 100% {
transform: translateY(0px);
}
50% {
transform: translateY(-10px);
}
}
.animate-fade-in-up {
animation: fadeInUp 0.6s ease-out;
}
.animate-float {
animation: float 3s ease-in-out infinite;
}
/* Loading state */
.loading-shimmer {
background: linear-gradient(90deg, #f0f0f0 25%, #e0e0e0 50%, #f0f0f0 75%);
background-size: 200% 100%;
animation: shimmer 1.5s infinite;
}
@keyframes shimmer {
0% {
background-position: -200% 0;
}
100% {
background-position: 200% 0;
}
}
</style>
</head> </head>
<body class="min-h-screen bg-gradient-to-br from-slate-50 via-blue-50 to-indigo-50 dark:from-gray-900 dark:via-gray-800 dark:to-gray-900 font-body text-gray-800 dark:text-gray-100 antialiased"> <body class="min-h-screen bg-gradient-to-br from-slate-50 via-blue-50 to-indigo-50 dark:from-gray-900 dark:via-gray-800 dark:to-gray-900 font-body text-gray-800 dark:text-gray-100 antialiased">
<!-- Background pattern overlay --> <!-- Background pattern overlay -->

View file

@ -455,7 +455,7 @@ try {
case 'biweekly': return 'Every Two Weeks'; case 'biweekly': return 'Every Two Weeks';
case 'monthly': return 'Monthly'; case 'monthly': return 'Monthly';
case 'first_tuesday': return 'First Tuesday of Month'; case 'first_tuesday': return 'First Tuesday of Month';
case '2nd/3rd Saturday Monthly': return '2nd/3rd Saturday Monthly'; case '2nd_3rd_saturday_monthly': return '2nd/3rd Saturday Monthly';
default: default:
// Capitalize first letter of each word // Capitalize first letter of each word
return type.split('_').map(word => word.charAt(0).toUpperCase() + word.slice(1)).join(' '); return type.split('_').map(word => word.charAt(0).toUpperCase() + word.slice(1)).join(' ');

View file

@ -72,7 +72,7 @@ try {
<div class="absolute bottom-32 left-1/4 w-40 h-40 bg-primary-300/10 rounded-full blur-2xl animate-float" style="animation-delay: 2s;"></div> <div class="absolute bottom-32 left-1/4 w-40 h-40 bg-primary-300/10 rounded-full blur-2xl animate-float" style="animation-delay: 2s;"></div>
</div> </div>
<div class="relative z-10 max-w-7xl mx-auto px-4 sm:px-6 lg:px-8 text-center text-white"> <div class="relative z-10 max-w-7xl mx-auto px-4 sm:px-6 lg:px-8 text-center text-white dark:text-white">
<div class="mb-8" data-animate> <div class="mb-8" data-animate>
<div class="inline-flex items-center space-x-2 bg-white/20 backdrop-blur-sm rounded-full px-6 py-3 mb-6"> <div class="inline-flex items-center space-x-2 bg-white/20 backdrop-blur-sm rounded-full px-6 py-3 mb-6">
<i data-lucide="sparkles" class="w-5 h-5 text-gold-400"></i> <i data-lucide="sparkles" class="w-5 h-5 text-gold-400"></i>
@ -83,7 +83,7 @@ try {
<span class="block text-white">{churchName}</span> <span class="block text-white">{churchName}</span>
</h1> </h1>
<p class="text-xl lg:text-2xl text-blue-100 mb-8 max-w-3xl mx-auto leading-relaxed"> <p class="text-xl lg:text-2xl text-blue-100 dark:text-blue-100 text-white mb-8 max-w-3xl mx-auto leading-relaxed">
{missionStatement} {missionStatement}
</p> </p>
@ -111,7 +111,7 @@ try {
</div> </div>
<!-- Service Times --> <!-- Service Times -->
<div class="flex flex-col sm:flex-row justify-center items-center space-y-4 sm:space-y-0 sm:space-x-8 text-blue-100" data-animate> <div class="flex flex-col sm:flex-row justify-center items-center space-y-4 sm:space-y-0 sm:space-x-8 text-white dark:text-blue-100" data-animate>
<div class="flex items-center space-x-2"> <div class="flex items-center space-x-2">
<i data-lucide="sun" class="w-5 h-5 text-gold-400"></i> <i data-lucide="sun" class="w-5 h-5 text-gold-400"></i>
<span>Sabbath School: {SERVICE_TIMES.SABBATH_SCHOOL}</span> <span>Sabbath School: {SERVICE_TIMES.SABBATH_SCHOOL}</span>
@ -387,7 +387,7 @@ try {
<div class="relative z-10 max-w-4xl mx-auto px-4 sm:px-6 lg:px-8 text-center" data-animate> <div class="relative z-10 max-w-4xl mx-auto px-4 sm:px-6 lg:px-8 text-center" data-animate>
<h2 class="text-4xl lg:text-5xl font-bold mb-6">Visit Us This Sabbath</h2> <h2 class="text-4xl lg:text-5xl font-bold mb-6">Visit Us This Sabbath</h2>
<p class="text-xl text-blue-100 mb-8 leading-relaxed"> <p class="text-xl text-white dark:text-blue-100 mb-8 leading-relaxed">
Experience the joy of Sabbath worship and discover the peace that comes from fellowship with God and His people Experience the joy of Sabbath worship and discover the peace that comes from fellowship with God and His people
</p> </p>

View file

@ -63,14 +63,20 @@ const allContent = [...sermons, ...livestreams];
{allContent.length > 0 ? ( {allContent.length > 0 ? (
<div class="grid md:grid-cols-2 lg:grid-cols-3 gap-8" id="sermons-grid"> <div class="grid md:grid-cols-2 lg:grid-cols-3 gap-8" id="sermons-grid">
{allContent.map(item => ( {allContent.map(item => {
<div const isLivestream = livestreams.includes(item);
class="sermon-card bg-gradient-to-br from-gray-50 to-blue-50 dark:from-gray-800 dark:to-gray-700 rounded-2xl p-6 hover:shadow-lg transition-all duration-300 hover:-translate-y-1 group" const category = isLivestream ? 'livestream' : 'sermon';
data-animate // Hide non-sermon items by default since "Sermons" tab is active
data-category={livestreams.includes(item) ? 'livestream' : 'sermon'} const hideByDefault = category !== 'sermon';
data-speaker={item.speaker}
data-date={item.date} return (
> <div
class={`sermon-card bg-gradient-to-br from-gray-50 to-blue-50 dark:from-gray-800 dark:to-gray-700 rounded-2xl p-6 hover:shadow-lg transition-all duration-300 hover:-translate-y-1 group${hideByDefault ? ' hidden' : ''}`}
data-animate
data-category={category}
data-speaker={item.speaker}
data-date={item.date}
>
<div class="w-16 h-16 bg-gradient-to-br from-primary-500 to-primary-600 rounded-2xl flex items-center justify-center mb-4 group-hover:scale-110 transition-transform"> <div class="w-16 h-16 bg-gradient-to-br from-primary-500 to-primary-600 rounded-2xl flex items-center justify-center mb-4 group-hover:scale-110 transition-transform">
<i data-lucide="play" class="w-8 h-8 text-white"></i> <i data-lucide="play" class="w-8 h-8 text-white"></i>
</div> </div>
@ -133,7 +139,8 @@ const allContent = [...sermons, ...livestreams];
)} )}
</div> </div>
</div> </div>
))} )
})}
</div> </div>
) : ( ) : (
<div class="text-center py-16"> <div class="text-center py-16">

View file

@ -0,0 +1,137 @@
@tailwind base;
@tailwind components;
@tailwind utilities;
/* Custom Styles for modern design */
/* Custom scrollbar for webkit browsers */
::-webkit-scrollbar {
width: 6px;
}
::-webkit-scrollbar-track {
background: #f1f5f9;
}
::-webkit-scrollbar-thumb {
background: #6366f1;
border-radius: 3px;
}
::-webkit-scrollbar-thumb:hover {
background: #4f46e5;
}
/* Smooth animations */
* {
transition: all 0.2s ease-in-out;
}
/* Focus states for accessibility */
:focus-visible {
outline: 2px solid #6366f1;
outline-offset: 2px;
}
/* Custom gradient backgrounds */
.bg-divine-gradient {
background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
}
.bg-heavenly-gradient {
background: linear-gradient(135deg, #6366f1 0%, #8b5cf6 50%, #a855f7 100%);
}
@media (prefers-color-scheme: light) {
.bg-heavenly-gradient {
background: linear-gradient(135deg, #4338ca 0%, #7c3aed 50%, #9333ea 100%);
}
}
.bg-sacred-gradient {
background: linear-gradient(135deg, #f59e0b 0%, #d97706 100%);
}
/* Text gradient utilities */
.text-divine-gradient {
background: linear-gradient(135deg, #6366f1 0%, #8b5cf6 100%);
-webkit-background-clip: text;
-webkit-text-fill-color: transparent;
background-clip: text;
}
@media (prefers-color-scheme: light) {
.text-divine-gradient {
background: linear-gradient(135deg, #4338ca 0%, #7c3aed 100%);
-webkit-background-clip: text;
-webkit-text-fill-color: transparent;
background-clip: text;
}
}
.text-golden-gradient {
background: linear-gradient(135deg, #f59e0b 0%, #d97706 100%);
-webkit-background-clip: text;
-webkit-text-fill-color: transparent;
background-clip: text;
}
@media (prefers-color-scheme: dark) {
::-webkit-scrollbar-track {
background: #1e293b;
}
}
/* Modern glass morphism effects */
.glass {
background: rgba(255, 255, 255, 0.25);
backdrop-filter: blur(10px);
border: 1px solid rgba(255, 255, 255, 0.18);
}
.glass-dark {
background: rgba(0, 0, 0, 0.25);
backdrop-filter: blur(10px);
border: 1px solid rgba(255, 255, 255, 0.1);
}
/* Custom animations */
@keyframes fadeInUp {
from {
opacity: 0;
transform: translateY(30px);
}
to {
opacity: 1;
transform: translateY(0);
}
}
@keyframes float {
0%, 100% {
transform: translateY(0px);
}
50% {
transform: translateY(-10px);
}
}
.animate-fade-in-up {
animation: fadeInUp 0.6s ease-out;
}
.animate-float {
animation: float 3s ease-in-out infinite;
}
/* Loading state */
.loading-shimmer {
background: linear-gradient(90deg, #f0f0f0 25%, #e0e0e0 50%, #f0f0f0 75%);
background-size: 200% 100%;
animation: shimmer 1.5s infinite;
}
@keyframes shimmer {
0% {
background-position: -200% 0;
}
100% {
background-position: 200% 0;
}
}

View file

@ -1,6 +1,7 @@
/** @type {import('tailwindcss').Config} */ /** @type {import('tailwindcss').Config} */
export default { export default {
content: ['./src/**/*.{astro,html,js,jsx,md,mdx,svelte,ts,tsx,vue}'], content: ['./src/**/*.{astro,html,js,jsx,md,mdx,svelte,ts,tsx,vue}'],
darkMode: 'media', // Use system preference for dark mode
theme: { theme: {
extend: { extend: {
colors: { colors: {

View file

@ -0,0 +1,124 @@
/** @type {import('tailwindcss').Config} */
export default {
content: ['./src/**/*.{astro,html,js,jsx,md,mdx,svelte,ts,tsx,vue}'],
theme: {
extend: {
colors: {
// Three Angels' Message inspired palette
primary: {
50: '#f0f4ff',
100: '#e0e7ff',
200: '#c7d2fe',
300: '#a5b4fc',
400: '#818cf8',
500: '#6366f1', // Primary indigo
600: '#4f46e5',
700: '#4338ca',
800: '#3730a3',
900: '#312e81',
950: '#1e1b4b'
},
// Sacred gold for highlights
gold: {
50: '#fffbeb',
100: '#fef3c7',
200: '#fde68a',
300: '#fcd34d',
400: '#fbbf24',
500: '#f59e0b', // Gold
600: '#d97706',
700: '#b45309',
800: '#92400e',
900: '#78350f'
},
// Pure whites and deep darks for contrast
heaven: {
50: '#ffffff',
100: '#fefefe',
200: '#fafafa',
300: '#f4f4f5'
},
earth: {
700: '#374151',
800: '#1f2937',
900: '#111827',
950: '#030712'
},
// Dark mode optimized colors - keep original light colors for dark backgrounds
blue: {
50: '#eff6ff',
100: '#dbeafe', // Original light blue - perfect for dark backgrounds
200: '#93c5fd',
300: '#60a5fa',
400: '#3b82f6',
500: '#2563eb',
600: '#1d4ed8',
700: '#1e40af',
800: '#1e3a8a',
900: '#1e3a8a',
950: '#172554'
},
gray: {
50: '#f9fafb',
100: '#f3f4f6', // Original light gray - perfect for dark backgrounds
200: '#e5e7eb',
300: '#d1d5db',
400: '#9ca3af',
500: '#6b7280',
600: '#4b5563',
700: '#374151',
800: '#1f2937',
900: '#111827',
950: '#030712'
}
},
fontFamily: {
// Modern, readable fonts
'display': ['Inter', 'system-ui', 'sans-serif'],
'body': ['Inter', 'system-ui', 'sans-serif'],
'serif': ['Playfair Display', 'Georgia', 'serif']
},
fontSize: {
'xs': ['0.75rem', { lineHeight: '1rem' }],
'sm': ['0.875rem', { lineHeight: '1.25rem' }],
'base': ['1rem', { lineHeight: '1.5rem' }],
'lg': ['1.125rem', { lineHeight: '1.75rem' }],
'xl': ['1.25rem', { lineHeight: '1.75rem' }],
'2xl': ['1.5rem', { lineHeight: '2rem' }],
'3xl': ['1.875rem', { lineHeight: '2.25rem' }],
'4xl': ['2.25rem', { lineHeight: '2.5rem' }],
'5xl': ['3rem', { lineHeight: '1' }],
'6xl': ['3.75rem', { lineHeight: '1' }],
'7xl': ['4.5rem', { lineHeight: '1' }],
'8xl': ['6rem', { lineHeight: '1' }],
'9xl': ['8rem', { lineHeight: '1' }]
},
animation: {
'fade-in': 'fadeIn 0.5s ease-in-out',
'slide-up': 'slideUp 0.6s ease-out',
'float': 'float 6s ease-in-out infinite'
},
keyframes: {
fadeIn: {
'0%': { opacity: '0' },
'100%': { opacity: '1' }
},
slideUp: {
'0%': { opacity: '0', transform: 'translateY(30px)' },
'100%': { opacity: '1', transform: 'translateY(0)' }
},
float: {
'0%, 100%': { transform: 'translateY(0px)' },
'50%': { transform: 'translateY(-20px)' }
}
},
boxShadow: {
'soft': '0 4px 6px -1px rgba(0, 0, 0, 0.1), 0 2px 4px -1px rgba(0, 0, 0, 0.06)',
'medium': '0 10px 15px -3px rgba(0, 0, 0, 0.1), 0 4px 6px -2px rgba(0, 0, 0, 0.05)',
'large': '0 25px 50px -12px rgba(0, 0, 0, 0.25)',
'divine': '0 0 50px rgba(99, 102, 241, 0.3)'
}
}
},
plugins: []
}

View file

@ -0,0 +1,124 @@
/** @type {import('tailwindcss').Config} */
export default {
content: ['./src/**/*.{astro,html,js,jsx,md,mdx,svelte,ts,tsx,vue}'],
theme: {
extend: {
colors: {
// Three Angels' Message inspired palette
primary: {
50: '#f0f4ff',
100: '#e0e7ff',
200: '#c7d2fe',
300: '#a5b4fc',
400: '#818cf8',
500: '#6366f1', // Primary indigo
600: '#4f46e5',
700: '#4338ca',
800: '#3730a3',
900: '#312e81',
950: '#1e1b4b'
},
// Sacred gold for highlights
gold: {
50: '#fffbeb',
100: '#fef3c7',
200: '#fde68a',
300: '#fcd34d',
400: '#fbbf24',
500: '#f59e0b', // Gold
600: '#d97706',
700: '#b45309',
800: '#92400e',
900: '#78350f'
},
// Pure whites and deep darks for contrast
heaven: {
50: '#ffffff',
100: '#fefefe',
200: '#fafafa',
300: '#f4f4f5'
},
earth: {
700: '#374151',
800: '#1f2937',
900: '#111827',
950: '#030712'
},
// Light mode optimized colors - replace problematic light colors
blue: {
50: '#eff6ff',
100: '#1e40af', // Much darker for visibility in light mode
200: '#93c5fd',
300: '#60a5fa',
400: '#3b82f6',
500: '#2563eb',
600: '#1d4ed8',
700: '#1e40af',
800: '#1e3a8a',
900: '#1e3a8a',
950: '#172554'
},
gray: {
50: '#f9fafb',
100: '#374151', // Much darker for visibility in light mode
200: '#e5e7eb',
300: '#d1d5db',
400: '#9ca3af',
500: '#6b7280',
600: '#4b5563',
700: '#374151',
800: '#1f2937',
900: '#111827',
950: '#030712'
}
},
fontFamily: {
// Modern, readable fonts
'display': ['Inter', 'system-ui', 'sans-serif'],
'body': ['Inter', 'system-ui', 'sans-serif'],
'serif': ['Playfair Display', 'Georgia', 'serif']
},
fontSize: {
'xs': ['0.75rem', { lineHeight: '1rem' }],
'sm': ['0.875rem', { lineHeight: '1.25rem' }],
'base': ['1rem', { lineHeight: '1.5rem' }],
'lg': ['1.125rem', { lineHeight: '1.75rem' }],
'xl': ['1.25rem', { lineHeight: '1.75rem' }],
'2xl': ['1.5rem', { lineHeight: '2rem' }],
'3xl': ['1.875rem', { lineHeight: '2.25rem' }],
'4xl': ['2.25rem', { lineHeight: '2.5rem' }],
'5xl': ['3rem', { lineHeight: '1' }],
'6xl': ['3.75rem', { lineHeight: '1' }],
'7xl': ['4.5rem', { lineHeight: '1' }],
'8xl': ['6rem', { lineHeight: '1' }],
'9xl': ['8rem', { lineHeight: '1' }]
},
animation: {
'fade-in': 'fadeIn 0.5s ease-in-out',
'slide-up': 'slideUp 0.6s ease-out',
'float': 'float 6s ease-in-out infinite'
},
keyframes: {
fadeIn: {
'0%': { opacity: '0' },
'100%': { opacity: '1' }
},
slideUp: {
'0%': { opacity: '0', transform: 'translateY(30px)' },
'100%': { opacity: '1', transform: 'translateY(0)' }
},
float: {
'0%, 100%': { transform: 'translateY(0px)' },
'50%': { transform: 'translateY(-20px)' }
}
},
boxShadow: {
'soft': '0 4px 6px -1px rgba(0, 0, 0, 0.1), 0 2px 4px -1px rgba(0, 0, 0, 0.06)',
'medium': '0 10px 15px -3px rgba(0, 0, 0, 0.1), 0 4px 6px -2px rgba(0, 0, 0, 0.05)',
'large': '0 25px 50px -12px rgba(0, 0, 0, 0.25)',
'divine': '0 0 50px rgba(99, 102, 241, 0.3)'
}
}
},
plugins: []
}