feat: Add contributing guidelines, license, and security policy documents
- Created CONTRIBUTING.md to outline contribution process and code of conduct. - Added LICENSE file with MIT License and third-party licenses. - Introduced SECURITY.md detailing vulnerability reporting and security measures. - Established README.md in assets directory for asset management and guidelines. - Implemented index.html as the main entry point for the website. - Configured package.json for project dependencies and scripts. - Developed styles.css for custom styles and responsive design. - Set up vite.config.ts for Vite configuration and build settings.
This commit is contained in:
190
CONTRIBUTING.md
Normal file
190
CONTRIBUTING.md
Normal file
@@ -0,0 +1,190 @@
|
|||||||
|
# Contributing to Miracles In Motion Website
|
||||||
|
|
||||||
|
Thank you for your interest in contributing to the Miracles In Motion website! This document provides guidelines for contributing to our project.
|
||||||
|
|
||||||
|
## Code of Conduct
|
||||||
|
|
||||||
|
We are committed to providing a welcoming and inspiring community for all. Please read and follow our Code of Conduct:
|
||||||
|
|
||||||
|
- Be respectful and inclusive
|
||||||
|
- Focus on what is best for the community
|
||||||
|
- Show empathy towards other community members
|
||||||
|
- Be collaborative
|
||||||
|
- Gracefully accept constructive feedback
|
||||||
|
|
||||||
|
## How to Contribute
|
||||||
|
|
||||||
|
### Reporting Issues
|
||||||
|
|
||||||
|
If you find a bug or have a suggestion for improvement:
|
||||||
|
|
||||||
|
1. Check if the issue already exists in our [GitHub Issues](https://github.com/Miracles-In-Motion/public-web/issues)
|
||||||
|
2. If not, create a new issue with:
|
||||||
|
- Clear, descriptive title
|
||||||
|
- Detailed description of the issue or suggestion
|
||||||
|
- Steps to reproduce (for bugs)
|
||||||
|
- Expected vs actual behavior
|
||||||
|
- Screenshots if applicable
|
||||||
|
- Browser and device information
|
||||||
|
|
||||||
|
### Contributing Code
|
||||||
|
|
||||||
|
1. **Fork the repository**
|
||||||
|
```bash
|
||||||
|
git clone https://github.com/Miracles-In-Motion/public-web.git
|
||||||
|
cd public-web
|
||||||
|
```
|
||||||
|
|
||||||
|
2. **Create a feature branch**
|
||||||
|
```bash
|
||||||
|
git checkout -b feature/your-feature-name
|
||||||
|
```
|
||||||
|
|
||||||
|
3. **Make your changes**
|
||||||
|
- Follow our coding standards (see below)
|
||||||
|
- Test your changes thoroughly
|
||||||
|
- Update documentation if needed
|
||||||
|
|
||||||
|
4. **Commit your changes**
|
||||||
|
```bash
|
||||||
|
git add .
|
||||||
|
git commit -m "feat: add new donation tracking feature"
|
||||||
|
```
|
||||||
|
|
||||||
|
5. **Push and create a Pull Request**
|
||||||
|
```bash
|
||||||
|
git push origin feature/your-feature-name
|
||||||
|
```
|
||||||
|
|
||||||
|
## Coding Standards
|
||||||
|
|
||||||
|
### HTML/CSS
|
||||||
|
- Use semantic HTML5 elements
|
||||||
|
- Follow accessibility guidelines (WCAG 2.1 AA)
|
||||||
|
- Use consistent indentation (2 spaces)
|
||||||
|
- Write meaningful class names
|
||||||
|
- Optimize for mobile-first responsive design
|
||||||
|
|
||||||
|
### JavaScript/React
|
||||||
|
- Use ES6+ features consistently
|
||||||
|
- Follow React best practices and hooks patterns
|
||||||
|
- Write descriptive variable and function names
|
||||||
|
- Add comments for complex logic
|
||||||
|
- Use consistent formatting (Prettier recommended)
|
||||||
|
|
||||||
|
### Content Guidelines
|
||||||
|
- Use inclusive, accessible language
|
||||||
|
- Maintain a compassionate, professional tone
|
||||||
|
- Ensure all content is factually accurate
|
||||||
|
- Include alt text for all images
|
||||||
|
- Keep content concise and scannable
|
||||||
|
|
||||||
|
## Testing
|
||||||
|
|
||||||
|
Before submitting a PR, please ensure:
|
||||||
|
|
||||||
|
- [ ] Website loads correctly on desktop and mobile
|
||||||
|
- [ ] All forms work properly
|
||||||
|
- [ ] Navigation functions correctly
|
||||||
|
- [ ] No console errors
|
||||||
|
- [ ] Content is accessible via screen readers
|
||||||
|
- [ ] Images have appropriate alt text
|
||||||
|
- [ ] Links work correctly
|
||||||
|
|
||||||
|
### Browser Testing
|
||||||
|
|
||||||
|
Please test your changes in:
|
||||||
|
- Chrome (latest)
|
||||||
|
- Firefox (latest)
|
||||||
|
- Safari (latest)
|
||||||
|
- Edge (latest)
|
||||||
|
- Mobile browsers (iOS Safari, Chrome Mobile)
|
||||||
|
|
||||||
|
## Accessibility
|
||||||
|
|
||||||
|
We strive to make our website accessible to everyone:
|
||||||
|
|
||||||
|
- Use semantic HTML
|
||||||
|
- Provide alt text for images
|
||||||
|
- Ensure proper color contrast
|
||||||
|
- Support keyboard navigation
|
||||||
|
- Test with screen readers
|
||||||
|
- Use ARIA labels when appropriate
|
||||||
|
|
||||||
|
## Performance
|
||||||
|
|
||||||
|
Optimize for fast loading:
|
||||||
|
- Compress images
|
||||||
|
- Minimize CSS/JS
|
||||||
|
- Use appropriate image formats (WebP when possible)
|
||||||
|
- Lazy load images below the fold
|
||||||
|
- Minimize HTTP requests
|
||||||
|
|
||||||
|
## Content Updates
|
||||||
|
|
||||||
|
For content changes:
|
||||||
|
|
||||||
|
### Donation Information
|
||||||
|
- Verify all donation links and amounts
|
||||||
|
- Test payment processing in sandbox mode
|
||||||
|
- Update impact statistics with current data
|
||||||
|
- Ensure EIN and legal information is current
|
||||||
|
|
||||||
|
### Program Information
|
||||||
|
- Work with program staff to verify accuracy
|
||||||
|
- Update statistics and beneficiary counts
|
||||||
|
- Include current testimonials and stories
|
||||||
|
- Maintain privacy of beneficiaries
|
||||||
|
|
||||||
|
### Legal Documents
|
||||||
|
- Have legal team review all policy changes
|
||||||
|
- Update effective dates
|
||||||
|
- Ensure compliance with state regulations
|
||||||
|
- Maintain transparency requirements
|
||||||
|
|
||||||
|
## Deployment
|
||||||
|
|
||||||
|
Our deployment process:
|
||||||
|
|
||||||
|
1. **Development**: Test locally with `npm run dev`
|
||||||
|
2. **Staging**: Deploy to staging environment for review
|
||||||
|
3. **Production**: Deploy to live site after approval
|
||||||
|
|
||||||
|
### Pre-deployment Checklist
|
||||||
|
|
||||||
|
- [ ] Content accuracy verified
|
||||||
|
- [ ] Links tested
|
||||||
|
- [ ] Forms tested
|
||||||
|
- [ ] Mobile responsiveness checked
|
||||||
|
- [ ] Accessibility tested
|
||||||
|
- [ ] Performance optimized
|
||||||
|
- [ ] Legal compliance confirmed
|
||||||
|
|
||||||
|
## Getting Help
|
||||||
|
|
||||||
|
If you need help:
|
||||||
|
|
||||||
|
- Check our [documentation](README.md)
|
||||||
|
- Review existing issues and PRs
|
||||||
|
- Contact the web team: web@miraclesinmotion.org
|
||||||
|
- Join our Slack channel: #website-dev
|
||||||
|
|
||||||
|
## Recognition
|
||||||
|
|
||||||
|
Contributors will be recognized:
|
||||||
|
|
||||||
|
- In our annual report (with permission)
|
||||||
|
- On our volunteer page
|
||||||
|
- In release notes for significant contributions
|
||||||
|
|
||||||
|
## License
|
||||||
|
|
||||||
|
By contributing, you agree that your contributions will be licensed under the same license as the project (MIT License).
|
||||||
|
|
||||||
|
## Questions?
|
||||||
|
|
||||||
|
Feel free to reach out:
|
||||||
|
- Email: web@miraclesinmotion.org
|
||||||
|
- GitHub Issues: [Create an issue](https://github.com/Miracles-In-Motion/public-web/issues/new)
|
||||||
|
|
||||||
|
Thank you for helping us create a better experience for our community! 💙
|
||||||
56
LICENSE
Normal file
56
LICENSE
Normal file
@@ -0,0 +1,56 @@
|
|||||||
|
MIT License
|
||||||
|
|
||||||
|
Copyright (c) 2024 Miracles In Motion
|
||||||
|
|
||||||
|
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
|
of this software and associated documentation files (the "Software"), to deal
|
||||||
|
in the Software without restriction, including without limitation the rights
|
||||||
|
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||||
|
copies of the Software, and to permit persons to whom the Software is
|
||||||
|
furnished to do so, subject to the following conditions:
|
||||||
|
|
||||||
|
The above copyright notice and this permission notice shall be included in all
|
||||||
|
copies or substantial portions of the Software.
|
||||||
|
|
||||||
|
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
|
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||||
|
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||||
|
SOFTWARE.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Third-Party Licenses
|
||||||
|
|
||||||
|
This project uses the following third-party libraries and resources:
|
||||||
|
|
||||||
|
### React
|
||||||
|
- License: MIT
|
||||||
|
- Copyright: Facebook, Inc. and its affiliates
|
||||||
|
- Website: https://reactjs.org/
|
||||||
|
|
||||||
|
### Tailwind CSS
|
||||||
|
- License: MIT
|
||||||
|
- Copyright: Tailwind Labs Inc.
|
||||||
|
- Website: https://tailwindcss.com/
|
||||||
|
|
||||||
|
### Framer Motion
|
||||||
|
- License: MIT
|
||||||
|
- Copyright: Framer B.V.
|
||||||
|
- Website: https://www.framer.com/motion/
|
||||||
|
|
||||||
|
### Font Awesome
|
||||||
|
- License: Font Awesome Free License
|
||||||
|
- Copyright: Fonticons, Inc.
|
||||||
|
- Website: https://fontawesome.com/
|
||||||
|
|
||||||
|
### Additional Notes
|
||||||
|
|
||||||
|
- All original content, including text, images, and branding, remains the property of Miracles In Motion
|
||||||
|
- The organization logo and branding materials are protected by trademark and are not covered under this MIT license
|
||||||
|
- User-generated content (testimonials, stories) remains the property of the original authors
|
||||||
|
- Donation processing and financial data are subject to additional privacy and security requirements
|
||||||
|
|
||||||
|
For questions about licensing, please contact: legal@miraclesinmotion.org
|
||||||
153
SECURITY.md
Normal file
153
SECURITY.md
Normal file
@@ -0,0 +1,153 @@
|
|||||||
|
# Security Policy
|
||||||
|
|
||||||
|
## Supported Versions
|
||||||
|
|
||||||
|
We actively maintain and provide security updates for the following versions:
|
||||||
|
|
||||||
|
| Version | Supported |
|
||||||
|
| ------- | ------------------ |
|
||||||
|
| 1.x.x | :white_check_mark: |
|
||||||
|
|
||||||
|
## Reporting a Vulnerability
|
||||||
|
|
||||||
|
The security and privacy of our users is our top priority. If you discover a security vulnerability in our website, please report it responsibly.
|
||||||
|
|
||||||
|
### How to Report
|
||||||
|
|
||||||
|
**Please do NOT create a public GitHub issue for security vulnerabilities.**
|
||||||
|
|
||||||
|
Instead, please:
|
||||||
|
|
||||||
|
1. **Email**: Send details to security@miraclesinmotion.org
|
||||||
|
2. **Subject Line**: "Security Vulnerability Report - [Brief Description]"
|
||||||
|
3. **Include**:
|
||||||
|
- Description of the vulnerability
|
||||||
|
- Steps to reproduce
|
||||||
|
- Potential impact
|
||||||
|
- Suggested remediation (if known)
|
||||||
|
- Your contact information
|
||||||
|
|
||||||
|
### What to Expect
|
||||||
|
|
||||||
|
- **Acknowledgment**: We'll acknowledge receipt within 24 hours
|
||||||
|
- **Initial Assessment**: We'll provide an initial assessment within 72 hours
|
||||||
|
- **Regular Updates**: We'll keep you informed of our progress
|
||||||
|
- **Timeline**: We aim to resolve critical issues within 7 days
|
||||||
|
- **Credit**: With your permission, we'll credit you in our security hall of fame
|
||||||
|
|
||||||
|
### Responsible Disclosure
|
||||||
|
|
||||||
|
We ask that you:
|
||||||
|
|
||||||
|
- Give us reasonable time to investigate and fix the issue
|
||||||
|
- Don't access, modify, or delete user data
|
||||||
|
- Don't perform actions that could negatively impact our users
|
||||||
|
- Don't publicly disclose the vulnerability until we've addressed it
|
||||||
|
|
||||||
|
## Security Measures
|
||||||
|
|
||||||
|
### Website Security
|
||||||
|
|
||||||
|
- **HTTPS**: All traffic encrypted with TLS 1.3
|
||||||
|
- **Content Security Policy**: Strict CSP headers implemented
|
||||||
|
- **XSS Protection**: Input sanitization and output encoding
|
||||||
|
- **CSRF Protection**: Anti-CSRF tokens on all forms
|
||||||
|
- **Security Headers**: Comprehensive security headers implemented
|
||||||
|
|
||||||
|
### Data Protection
|
||||||
|
|
||||||
|
- **Minimal Collection**: We only collect necessary information
|
||||||
|
- **Encryption**: Sensitive data encrypted at rest and in transit
|
||||||
|
- **Access Controls**: Role-based access to sensitive systems
|
||||||
|
- **Regular Audits**: Quarterly security assessments
|
||||||
|
|
||||||
|
### Donation Security
|
||||||
|
|
||||||
|
- **PCI Compliance**: Payment processing meets PCI DSS standards
|
||||||
|
- **Third-Party Processors**: We use certified payment processors
|
||||||
|
- **No Storage**: We don't store payment card information
|
||||||
|
- **Fraud Prevention**: Advanced fraud detection systems
|
||||||
|
|
||||||
|
### Privacy Protection
|
||||||
|
|
||||||
|
- **Data Minimization**: Collect only what's necessary
|
||||||
|
- **Purpose Limitation**: Use data only for stated purposes
|
||||||
|
- **Retention Policies**: Regular data cleanup and deletion
|
||||||
|
- **User Rights**: Easy access, correction, and deletion requests
|
||||||
|
|
||||||
|
## Vulnerability Categories
|
||||||
|
|
||||||
|
### Critical (24-48 hour response)
|
||||||
|
|
||||||
|
- Remote code execution
|
||||||
|
- SQL injection
|
||||||
|
- Authentication bypass
|
||||||
|
- Privilege escalation
|
||||||
|
- Payment system vulnerabilities
|
||||||
|
|
||||||
|
### High (72 hour response)
|
||||||
|
|
||||||
|
- Cross-site scripting (XSS)
|
||||||
|
- Cross-site request forgery (CSRF)
|
||||||
|
- Sensitive data exposure
|
||||||
|
- Broken access controls
|
||||||
|
|
||||||
|
### Medium (1 week response)
|
||||||
|
|
||||||
|
- Security misconfigurations
|
||||||
|
- Insecure direct object references
|
||||||
|
- Information disclosure
|
||||||
|
- Missing security headers
|
||||||
|
|
||||||
|
### Low (2 week response)
|
||||||
|
|
||||||
|
- Clickjacking
|
||||||
|
- Minor information leakage
|
||||||
|
- Insecure cookies
|
||||||
|
- Missing rate limiting
|
||||||
|
|
||||||
|
## Security Best Practices for Contributors
|
||||||
|
|
||||||
|
### Code Security
|
||||||
|
|
||||||
|
- Validate all user inputs
|
||||||
|
- Use parameterized queries
|
||||||
|
- Implement proper authentication
|
||||||
|
- Follow principle of least privilege
|
||||||
|
- Keep dependencies updated
|
||||||
|
|
||||||
|
### Infrastructure Security
|
||||||
|
|
||||||
|
- Use environment variables for secrets
|
||||||
|
- Implement proper logging
|
||||||
|
- Monitor for unusual activity
|
||||||
|
- Regular security updates
|
||||||
|
- Backup and recovery procedures
|
||||||
|
|
||||||
|
## Security Contact
|
||||||
|
|
||||||
|
- **Email**: security@miraclesinmotion.org
|
||||||
|
- **Response Time**: 24 hours for acknowledgment
|
||||||
|
- **GPG Key**: Available upon request
|
||||||
|
|
||||||
|
## Legal Protection
|
||||||
|
|
||||||
|
We support responsible disclosure and will not pursue legal action against researchers who:
|
||||||
|
|
||||||
|
- Follow this security policy
|
||||||
|
- Don't access user data unnecessarily
|
||||||
|
- Don't disrupt our services
|
||||||
|
- Report vulnerabilities in good faith
|
||||||
|
|
||||||
|
## Updates
|
||||||
|
|
||||||
|
This security policy is reviewed quarterly and updated as needed. Last updated: October 2024.
|
||||||
|
|
||||||
|
## Recognition
|
||||||
|
|
||||||
|
We maintain a security hall of fame to recognize researchers who help improve our security:
|
||||||
|
|
||||||
|
### 2024 Contributors
|
||||||
|
*We'll update this section as vulnerabilities are responsibly disclosed and resolved.*
|
||||||
|
|
||||||
|
Thank you for helping keep Miracles In Motion and our community safe! 🔒
|
||||||
158
assets/README.md
Normal file
158
assets/README.md
Normal file
@@ -0,0 +1,158 @@
|
|||||||
|
# Required Assets for Miracles In Motion Website
|
||||||
|
|
||||||
|
This directory contains all the assets needed for the website to function properly.
|
||||||
|
|
||||||
|
## Images Directory Structure
|
||||||
|
|
||||||
|
```
|
||||||
|
assets/images/
|
||||||
|
├── logo.png # Main organization logo (200x200px recommended)
|
||||||
|
├── logo-white.png # White version for dark backgrounds
|
||||||
|
├── favicon.ico # Website favicon (32x32px)
|
||||||
|
├── hero-bg.jpg # Hero section background image (1920x1080px)
|
||||||
|
├── og-image.jpg # Open Graph image for social sharing (1200x630px)
|
||||||
|
├── team/ # Team member photos
|
||||||
|
│ ├── director-1.jpg
|
||||||
|
│ ├── director-2.jpg
|
||||||
|
│ └── volunteer-1.jpg
|
||||||
|
├── impact/ # Photos showing impact
|
||||||
|
│ ├── students-1.jpg
|
||||||
|
│ ├── supplies-1.jpg
|
||||||
|
│ └── distribution-1.jpg
|
||||||
|
└── sponsors/ # Sponsor/partner logos
|
||||||
|
├── school-district.png
|
||||||
|
├── local-business.png
|
||||||
|
└── community-org.png
|
||||||
|
```
|
||||||
|
|
||||||
|
## Documents Directory
|
||||||
|
|
||||||
|
```
|
||||||
|
assets/documents/
|
||||||
|
├── 501c3-certificate.pdf # IRS determination letter
|
||||||
|
├── financial-report.pdf # Latest annual financial report
|
||||||
|
├── form-990.pdf # Latest Form 990
|
||||||
|
├── privacy-policy.pdf # Privacy policy document
|
||||||
|
├── terms-of-service.pdf # Terms of service
|
||||||
|
├── donor-privacy-policy.pdf # Donor privacy policy
|
||||||
|
├── volunteer-handbook.pdf # Volunteer handbook
|
||||||
|
├── gift-acceptance-policy.pdf # Gift acceptance policy
|
||||||
|
├── annual-report-2024.pdf # Latest annual report
|
||||||
|
└── impact-report-2024.pdf # Impact measurement report
|
||||||
|
```
|
||||||
|
|
||||||
|
## Image Specifications
|
||||||
|
|
||||||
|
### Logo Requirements
|
||||||
|
- **Format**: PNG with transparency
|
||||||
|
- **Size**: 200x200px (minimum), SVG preferred
|
||||||
|
- **Variants**: Color, white, and dark versions
|
||||||
|
- **Usage**: Navigation, footer, social sharing
|
||||||
|
|
||||||
|
### Hero Images
|
||||||
|
- **Format**: WebP preferred, JPG fallback
|
||||||
|
- **Size**: 1920x1080px minimum
|
||||||
|
- **Quality**: High quality, compressed for web
|
||||||
|
- **Content**: Students, supplies, or community impact
|
||||||
|
|
||||||
|
### Team Photos
|
||||||
|
- **Format**: WebP preferred, JPG fallback
|
||||||
|
- **Size**: 400x400px minimum
|
||||||
|
- **Style**: Professional, consistent lighting
|
||||||
|
- **Requirements**: Signed photo releases on file
|
||||||
|
|
||||||
|
### Impact Photos
|
||||||
|
- **Format**: WebP preferred, JPG fallback
|
||||||
|
- **Size**: Various sizes for responsive design
|
||||||
|
- **Privacy**: No identifiable students without permission
|
||||||
|
- **Alt Text**: Descriptive text for accessibility
|
||||||
|
|
||||||
|
## Content Guidelines
|
||||||
|
|
||||||
|
### Photography
|
||||||
|
- Focus on positive, uplifting imagery
|
||||||
|
- Show diverse representation
|
||||||
|
- Maintain dignity and respect for all subjects
|
||||||
|
- Obtain proper releases for all identifiable people
|
||||||
|
- Follow child protection policies
|
||||||
|
|
||||||
|
### Document Standards
|
||||||
|
- **Format**: PDF preferred for official documents
|
||||||
|
- **Accessibility**: Ensure PDFs are accessible
|
||||||
|
- **Size**: Optimize for web delivery
|
||||||
|
- **Updates**: Keep current versions, archive old ones
|
||||||
|
|
||||||
|
## File Naming Convention
|
||||||
|
|
||||||
|
- Use lowercase letters
|
||||||
|
- Use hyphens for spaces
|
||||||
|
- Include version dates for documents
|
||||||
|
- Be descriptive but concise
|
||||||
|
|
||||||
|
Examples:
|
||||||
|
- `annual-report-2024.pdf`
|
||||||
|
- `hero-students-supplies.jpg`
|
||||||
|
- `team-sarah-director.jpg`
|
||||||
|
- `logo-miracles-in-motion.png`
|
||||||
|
|
||||||
|
## Optimization
|
||||||
|
|
||||||
|
### Images
|
||||||
|
- Compress images without quality loss
|
||||||
|
- Use appropriate formats (WebP > JPG > PNG)
|
||||||
|
- Generate multiple sizes for responsive design
|
||||||
|
- Include alt text for accessibility
|
||||||
|
|
||||||
|
### Documents
|
||||||
|
- Keep file sizes reasonable for download
|
||||||
|
- Ensure accessibility compliance
|
||||||
|
- Version control for updates
|
||||||
|
- Consider bandwidth limitations
|
||||||
|
|
||||||
|
## Legal Considerations
|
||||||
|
|
||||||
|
### Photo Releases
|
||||||
|
- Required for all identifiable people
|
||||||
|
- Special requirements for minors
|
||||||
|
- Store releases securely
|
||||||
|
- Respect usage limitations
|
||||||
|
|
||||||
|
### Copyright
|
||||||
|
- Only use images we own or have licensed
|
||||||
|
- Credit photographers when required
|
||||||
|
- Respect usage restrictions
|
||||||
|
- Maintain license documentation
|
||||||
|
|
||||||
|
### Privacy
|
||||||
|
- Protect student privacy
|
||||||
|
- Follow FERPA guidelines
|
||||||
|
- Blur faces when necessary
|
||||||
|
- Remove metadata that could identify locations
|
||||||
|
|
||||||
|
## Missing Asset Placeholders
|
||||||
|
|
||||||
|
Until actual assets are available, the website will use:
|
||||||
|
- CSS-generated logos and icons
|
||||||
|
- Placeholder images
|
||||||
|
- Generic backgrounds
|
||||||
|
- Font-based icons
|
||||||
|
|
||||||
|
## Getting Assets
|
||||||
|
|
||||||
|
To obtain proper assets for this website:
|
||||||
|
|
||||||
|
1. **Logo**: Contact the organization's brand manager
|
||||||
|
2. **Photos**: Coordinate with program staff for approved images
|
||||||
|
3. **Documents**: Request from legal/administrative team
|
||||||
|
4. **Approval**: All assets must be approved before use
|
||||||
|
|
||||||
|
## Updates
|
||||||
|
|
||||||
|
This asset list should be updated when:
|
||||||
|
- New programs launch
|
||||||
|
- Staff changes occur
|
||||||
|
- Legal documents are updated
|
||||||
|
- Annual reports are published
|
||||||
|
- New partnerships are formed
|
||||||
|
|
||||||
|
For questions about assets, contact: web@miraclesinmotion.org
|
||||||
68
index.html
Normal file
68
index.html
Normal file
@@ -0,0 +1,68 @@
|
|||||||
|
<!DOCTYPE html>
|
||||||
|
<html lang="en">
|
||||||
|
<head>
|
||||||
|
<meta charset="UTF-8">
|
||||||
|
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||||
|
<title>Miracles In Motion | 501(c)3 Non-Profit Organization</title>
|
||||||
|
<meta name="description" content="Miracles In Motion is a 501(c)3 non-profit organization dedicated to creating positive change in our community through compassionate action and support.">
|
||||||
|
<meta name="keywords" content="non-profit, charity, 501c3, miracles in motion, community support, donations, volunteers">
|
||||||
|
|
||||||
|
<!-- Open Graph Meta Tags -->
|
||||||
|
<meta property="og:title" content="Miracles In Motion | 501(c)3 Non-Profit Organization">
|
||||||
|
<meta property="og:description" content="Creating positive change in our community through compassionate action and support.">
|
||||||
|
<meta property="og:type" content="website">
|
||||||
|
<meta property="og:url" content="https://miraclesinmotion.org">
|
||||||
|
|
||||||
|
<!-- Favicon -->
|
||||||
|
<link rel="icon" type="image/x-icon" href="/favicon.ico">
|
||||||
|
|
||||||
|
<!-- Tailwind CSS -->
|
||||||
|
<script src="https://cdn.tailwindcss.com"></script>
|
||||||
|
|
||||||
|
<!-- React and Babel -->
|
||||||
|
<script crossorigin src="https://unpkg.com/react@18/umd/react.production.min.js"></script>
|
||||||
|
<script crossorigin src="https://unpkg.com/react-dom@18/umd/react-dom.production.min.js"></script>
|
||||||
|
<script src="https://unpkg.com/@babel/standalone/babel.min.js"></script>
|
||||||
|
|
||||||
|
<!-- Framer Motion -->
|
||||||
|
<script src="https://unpkg.com/framer-motion@10/dist/framer-motion.js"></script>
|
||||||
|
|
||||||
|
<!-- Font Awesome for Icons -->
|
||||||
|
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.4.0/css/all.min.css">
|
||||||
|
|
||||||
|
<style>
|
||||||
|
body {
|
||||||
|
font-family: 'Inter', -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif;
|
||||||
|
}
|
||||||
|
|
||||||
|
.gradient-text {
|
||||||
|
background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
|
||||||
|
-webkit-background-clip: text;
|
||||||
|
-webkit-text-fill-color: transparent;
|
||||||
|
background-clip: text;
|
||||||
|
}
|
||||||
|
|
||||||
|
.hero-gradient {
|
||||||
|
background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
|
||||||
|
}
|
||||||
|
|
||||||
|
.card-hover {
|
||||||
|
transition: all 0.3s ease;
|
||||||
|
}
|
||||||
|
|
||||||
|
.card-hover:hover {
|
||||||
|
transform: translateY(-8px);
|
||||||
|
box-shadow: 0 20px 40px rgba(0,0,0,0.1);
|
||||||
|
}
|
||||||
|
|
||||||
|
.smooth-scroll {
|
||||||
|
scroll-behavior: smooth;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
</head>
|
||||||
|
<body class="smooth-scroll">
|
||||||
|
<div id="root"></div>
|
||||||
|
|
||||||
|
<script type="text/babel" src="mim_web.jsx"></script>
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
277
mim_web.jsx
277
mim_web.jsx
@@ -1,35 +1,11 @@
|
|||||||
import React, { useEffect, useMemo, useRef, useState } from "react";
|
const { React, ReactDOM } = window;
|
||||||
import { motion, useMotionValue, useSpring, useTransform } from "framer-motion";
|
const { useState, useEffect, useRef, useMemo } = React;
|
||||||
import {
|
const { motion, AnimatePresence } = window.FramerMotion || {};
|
||||||
ArrowRight,
|
|
||||||
Backpack,
|
|
||||||
CheckCircle2,
|
|
||||||
Facebook,
|
|
||||||
Globe,
|
|
||||||
HandHeart,
|
|
||||||
Heart,
|
|
||||||
Instagram,
|
|
||||||
Mail,
|
|
||||||
MapPin,
|
|
||||||
Moon,
|
|
||||||
Phone,
|
|
||||||
Shirt,
|
|
||||||
Sparkles,
|
|
||||||
Star,
|
|
||||||
SunMedium,
|
|
||||||
Users,
|
|
||||||
Building2,
|
|
||||||
BookOpenText,
|
|
||||||
Quote,
|
|
||||||
FileText,
|
|
||||||
ShieldCheck,
|
|
||||||
} from "lucide-react";
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Miracles in Motion — Tailwind + React single-file site
|
* Miracles in Motion — Complete Non-Profit Website
|
||||||
* Now includes a tiny hash router, dedicated pages (Donate, Volunteers, Sponsors,
|
* A comprehensive 501(c)3 organization website with modern design,
|
||||||
* Stories, Testimonies, Legal), cookie banner w/ consent, analytics loader,
|
* donation processing, volunteer management, and impact tracking.
|
||||||
* and accessibility-minded forms + policies. Keep it serverless-friendly.
|
|
||||||
*/
|
*/
|
||||||
|
|
||||||
/* ===================== Router ===================== */
|
/* ===================== Router ===================== */
|
||||||
@@ -44,9 +20,41 @@ function useHashRoute() {
|
|||||||
return route;
|
return route;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* ===================== Icons ===================== */
|
||||||
|
const Icons = {
|
||||||
|
Heart: () => React.createElement('i', { className: 'fas fa-heart' }),
|
||||||
|
HandHeart: () => React.createElement('i', { className: 'fas fa-hand-holding-heart' }),
|
||||||
|
Users: () => React.createElement('i', { className: 'fas fa-users' }),
|
||||||
|
Globe: () => React.createElement('i', { className: 'fas fa-globe' }),
|
||||||
|
Star: () => React.createElement('i', { className: 'fas fa-star' }),
|
||||||
|
CheckCircle: () => React.createElement('i', { className: 'fas fa-check-circle' }),
|
||||||
|
Mail: () => React.createElement('i', { className: 'fas fa-envelope' }),
|
||||||
|
Phone: () => React.createElement('i', { className: 'fas fa-phone' }),
|
||||||
|
MapPin: () => React.createElement('i', { className: 'fas fa-map-marker-alt' }),
|
||||||
|
Facebook: () => React.createElement('i', { className: 'fab fa-facebook-f' }),
|
||||||
|
Instagram: () => React.createElement('i', { className: 'fab fa-instagram' }),
|
||||||
|
Twitter: () => React.createElement('i', { className: 'fab fa-twitter' }),
|
||||||
|
LinkedIn: () => React.createElement('i', { className: 'fab fa-linkedin-in' }),
|
||||||
|
ArrowRight: () => React.createElement('i', { className: 'fas fa-arrow-right' }),
|
||||||
|
Menu: () => React.createElement('i', { className: 'fas fa-bars' }),
|
||||||
|
Close: () => React.createElement('i', { className: 'fas fa-times' }),
|
||||||
|
Donate: () => React.createElement('i', { className: 'fas fa-donate' }),
|
||||||
|
Volunteer: () => React.createElement('i', { className: 'fas fa-hands-helping' }),
|
||||||
|
Calendar: () => React.createElement('i', { className: 'fas fa-calendar-alt' }),
|
||||||
|
Award: () => React.createElement('i', { className: 'fas fa-award' }),
|
||||||
|
Shield: () => React.createElement('i', { className: 'fas fa-shield-alt' }),
|
||||||
|
FileText: () => React.createElement('i', { className: 'fas fa-file-text' }),
|
||||||
|
Quote: () => React.createElement('i', { className: 'fas fa-quote-left' }),
|
||||||
|
ChevronDown: () => React.createElement('i', { className: 'fas fa-chevron-down' }),
|
||||||
|
ExternalLink: () => React.createElement('i', { className: 'fas fa-external-link-alt' }),
|
||||||
|
};
|
||||||
|
|
||||||
|
/* ===================== Main App ===================== */
|
||||||
export default function MiraclesInMotionSite() {
|
export default function MiraclesInMotionSite() {
|
||||||
const [dark, setDark] = useState(true);
|
const [darkMode, setDarkMode] = useState(false);
|
||||||
|
const [mobileMenuOpen, setMobileMenuOpen] = useState(false);
|
||||||
const route = useHashRoute();
|
const route = useHashRoute();
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
document.title =
|
document.title =
|
||||||
route === "/"
|
route === "/"
|
||||||
@@ -73,7 +81,7 @@ export default function MiraclesInMotionSite() {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
function Router({ route }: { route: string }) {
|
function Router({ route }) {
|
||||||
switch (route) {
|
switch (route) {
|
||||||
case "/":
|
case "/":
|
||||||
return <HomePage />;
|
return <HomePage />;
|
||||||
@@ -106,7 +114,7 @@ function SkipToContent() {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
function Nav({ dark, onToggleDark }: { dark: boolean; onToggleDark: () => void }) {
|
function Nav({ darkMode, setDarkMode, mobileMenuOpen, setMobileMenuOpen }) {
|
||||||
return (
|
return (
|
||||||
<nav className="mx-auto flex w-full max-w-7xl items-center justify-between px-4 py-3 sm:px-6 lg:px-8">
|
<nav className="mx-auto flex w-full max-w-7xl items-center justify-between px-4 py-3 sm:px-6 lg:px-8">
|
||||||
<div className="flex items-center gap-3">
|
<div className="flex items-center gap-3">
|
||||||
@@ -239,7 +247,7 @@ function HeroShowcase() {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
function TiltCard({ icon: Icon, title, desc }: { icon: any; title: string; desc: string }) {
|
function TiltCard({ icon: Icon, title, desc }) {
|
||||||
const x = useMotionValue(0);
|
const x = useMotionValue(0);
|
||||||
const y = useMotionValue(0);
|
const y = useMotionValue(0);
|
||||||
const rx = useTransform(y, [-50, 50], [8, -8]);
|
const rx = useTransform(y, [-50, 50], [8, -8]);
|
||||||
@@ -250,7 +258,7 @@ function TiltCard({ icon: Icon, title, desc }: { icon: any; title: string; desc:
|
|||||||
return (
|
return (
|
||||||
<motion.div
|
<motion.div
|
||||||
onMouseMove={(e) => {
|
onMouseMove={(e) => {
|
||||||
const rect = (e.currentTarget as HTMLElement).getBoundingClientRect();
|
const rect = e.currentTarget.getBoundingClientRect();
|
||||||
x.set(e.clientX - rect.left - rect.width / 2);
|
x.set(e.clientX - rect.left - rect.width / 2);
|
||||||
y.set(e.clientY - rect.top - rect.height / 2);
|
y.set(e.clientY - rect.top - rect.height / 2);
|
||||||
}}
|
}}
|
||||||
@@ -322,7 +330,7 @@ function Programs() {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
function FeatureCard({ icon: Icon, title, body }: { icon: any; title: string; body: string }) {
|
function FeatureCard({ icon: Icon, title, body }) {
|
||||||
return (
|
return (
|
||||||
<div className="group relative overflow-hidden rounded-2xl border border-white/30 bg-white/70 p-6 shadow-xl backdrop-blur transition hover:-translate-y-0.5 hover:shadow-2xl dark:border-white/10 dark:bg-white/5">
|
<div className="group relative overflow-hidden rounded-2xl border border-white/30 bg-white/70 p-6 shadow-xl backdrop-blur transition hover:-translate-y-0.5 hover:shadow-2xl dark:border-white/10 dark:bg-white/5">
|
||||||
<div className="absolute left-1/2 top-0 -z-10 h-40 w-40 -translate-x-1/2 rounded-full bg-gradient-to-br from-fuchsia-500/20 to-indigo-500/20 blur-2xl" />
|
<div className="absolute left-1/2 top-0 -z-10 h-40 w-40 -translate-x-1/2 rounded-full bg-gradient-to-br from-fuchsia-500/20 to-indigo-500/20 blur-2xl" />
|
||||||
@@ -375,7 +383,7 @@ function Impact() {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
function Stat({ label, value }: { label: string; value: number }) {
|
function Stat({ label, value }) {
|
||||||
return (
|
return (
|
||||||
<div className="relative overflow-hidden rounded-2xl border border-white/30 bg-white/70 p-6 text-center shadow-xl backdrop-blur dark:border-white/10 dark:bg-white/5">
|
<div className="relative overflow-hidden rounded-2xl border border-white/30 bg-white/70 p-6 text-center shadow-xl backdrop-blur dark:border-white/10 dark:bg-white/5">
|
||||||
<div className="absolute -right-10 -top-10 h-28 w-28 rounded-full bg-gradient-to-br from-fuchsia-500/20 to-indigo-500/20 blur-2xl" />
|
<div className="absolute -right-10 -top-10 h-28 w-28 rounded-full bg-gradient-to-br from-fuchsia-500/20 to-indigo-500/20 blur-2xl" />
|
||||||
@@ -387,7 +395,7 @@ function Stat({ label, value }: { label: string; value: number }) {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
function AnimatedNumber({ value }: { value: number }) {
|
function AnimatedNumber({ value }) {
|
||||||
const mv = useMotionValue(0);
|
const mv = useMotionValue(0);
|
||||||
const spring = useSpring(mv, { stiffness: 90, damping: 15 });
|
const spring = useSpring(mv, { stiffness: 90, damping: 15 });
|
||||||
const rounded = useTransform(spring, (latest) => Math.floor(latest).toLocaleString());
|
const rounded = useTransform(spring, (latest) => Math.floor(latest).toLocaleString());
|
||||||
@@ -483,7 +491,7 @@ function GetInvolved() {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
function Callout({ title, body, href, accent, icon: Icon }: { title: string; body: string; href: string; accent: string; icon: any }) {
|
function Callout({ title, body, href, accent, icon: Icon }) {
|
||||||
return (
|
return (
|
||||||
<div className="group relative overflow-hidden rounded-2xl border border-white/30 bg-white/70 p-6 shadow-xl backdrop-blur transition hover:-translate-y-0.5 hover:shadow-2xl dark:border-white/10 dark:bg-white/5">
|
<div className="group relative overflow-hidden rounded-2xl border border-white/30 bg-white/70 p-6 shadow-xl backdrop-blur transition hover:-translate-y-0.5 hover:shadow-2xl dark:border-white/10 dark:bg-white/5">
|
||||||
<div className={`absolute -right-10 -top-10 h-36 w-36 rounded-full bg-gradient-to-br ${accent} opacity-30 blur-2xl`} />
|
<div className={`absolute -right-10 -top-10 h-36 w-36 rounded-full bg-gradient-to-br ${accent} opacity-30 blur-2xl`} />
|
||||||
@@ -531,7 +539,7 @@ function CTA() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/* ===================== New Pages ===================== */
|
/* ===================== New Pages ===================== */
|
||||||
function PageShell({ title, icon: Icon, eyebrow, children, cta }: { title: string; icon: any; eyebrow?: string; children: React.ReactNode; cta?: React.ReactNode }) {
|
function PageShell({ title, icon: Icon, eyebrow, children, cta }) {
|
||||||
return (
|
return (
|
||||||
<section className="relative py-16 sm:py-24">
|
<section className="relative py-16 sm:py-24">
|
||||||
<div className="mx-auto max-w-6xl px-4 sm:px-6 lg:px-8">
|
<div className="mx-auto max-w-6xl px-4 sm:px-6 lg:px-8">
|
||||||
@@ -807,6 +815,191 @@ function LegalPage() {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
function PolicySection({ id, title, children }: { id: string; title: string; children: React.ReactNode }) {
|
/* ===================== Helper Components ===================== */
|
||||||
|
function PolicySection({ id, title, children }) {
|
||||||
return (
|
return (
|
||||||
<section id={id} className="rounded-2xl border bord
|
<section id={id} className="rounded-2xl border border-white/30 bg-white/70 p-6 dark:border-white/10 dark:bg-white/5">
|
||||||
|
<h2 className="font-semibold tracking-tight">{title}</h2>
|
||||||
|
<div className="mt-3 space-y-3 text-sm text-neutral-700 dark:text-neutral-300">{children}</div>
|
||||||
|
</section>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
function SectionHeader({ eyebrow, title, subtitle }) {
|
||||||
|
return (
|
||||||
|
<div className="mx-auto max-w-3xl text-center">
|
||||||
|
{eyebrow && <div className="text-sm uppercase tracking-wider text-fuchsia-600 dark:text-fuchsia-400">{eyebrow}</div>}
|
||||||
|
<h2 className="mt-2 text-3xl font-bold tracking-tight sm:text-4xl">{title}</h2>
|
||||||
|
{subtitle && <p className="mt-4 text-lg text-neutral-600 dark:text-neutral-300">{subtitle}</p>}
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
function Card({ title, icon: Icon, children }) {
|
||||||
|
return (
|
||||||
|
<div className="rounded-2xl border border-white/30 bg-white/70 p-6 dark:border-white/10 dark:bg-white/5">
|
||||||
|
<div className="flex items-center gap-3">
|
||||||
|
<div className="grid h-10 w-10 place-items-center rounded-xl bg-gradient-to-br from-fuchsia-500 to-indigo-500 text-white shadow">
|
||||||
|
<Icon className="h-5 w-5" />
|
||||||
|
</div>
|
||||||
|
<div className="font-semibold tracking-tight">{title}</div>
|
||||||
|
</div>
|
||||||
|
<div className="mt-3">{children}</div>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
function NotFoundPage() {
|
||||||
|
return (
|
||||||
|
<section className="relative py-24">
|
||||||
|
<div className="mx-auto max-w-md px-4 text-center sm:px-6 lg:px-8">
|
||||||
|
<h1 className="text-6xl font-bold text-neutral-300 dark:text-neutral-700">404</h1>
|
||||||
|
<h2 className="mt-4 text-2xl font-semibold">Page not found</h2>
|
||||||
|
<p className="mt-2 text-neutral-600 dark:text-neutral-400">
|
||||||
|
The page you're looking for doesn't exist.
|
||||||
|
</p>
|
||||||
|
<a href="#/" className="btn-primary mt-6">
|
||||||
|
Go home
|
||||||
|
</a>
|
||||||
|
</div>
|
||||||
|
</section>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
function BackgroundDecor() {
|
||||||
|
return (
|
||||||
|
<div className="pointer-events-none fixed inset-0 overflow-hidden">
|
||||||
|
<div className="absolute -top-40 -right-40 h-80 w-80 rounded-full bg-gradient-to-br from-fuchsia-400/20 to-violet-600/20 blur-3xl" />
|
||||||
|
<div className="absolute -bottom-40 -left-40 h-80 w-80 rounded-full bg-gradient-to-tr from-indigo-400/20 to-sky-600/20 blur-3xl" />
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
function Footer() {
|
||||||
|
return (
|
||||||
|
<footer className="relative mt-24 border-t border-white/30 bg-white/50 backdrop-blur dark:border-white/10 dark:bg-white/5">
|
||||||
|
<div className="mx-auto max-w-7xl px-4 py-12 sm:px-6 lg:px-8">
|
||||||
|
<div className="grid gap-8 lg:grid-cols-4">
|
||||||
|
<div className="lg:col-span-2">
|
||||||
|
<div className="flex items-center gap-3">
|
||||||
|
<LogoMark />
|
||||||
|
<div>
|
||||||
|
<div className="font-semibold">Miracles in Motion</div>
|
||||||
|
<div className="text-sm text-neutral-600 dark:text-neutral-400">Essentials for every student</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<p className="mt-4 max-w-md text-sm text-neutral-600 dark:text-neutral-400">
|
||||||
|
A 501(c)(3) nonprofit providing students with school supplies, clothing, and emergency support to help them succeed.
|
||||||
|
</p>
|
||||||
|
<div className="mt-4 flex gap-4">
|
||||||
|
<a href="#" className="text-neutral-600 hover:text-fuchsia-600 dark:text-neutral-400">
|
||||||
|
<Icons.Facebook />
|
||||||
|
</a>
|
||||||
|
<a href="#" className="text-neutral-600 hover:text-fuchsia-600 dark:text-neutral-400">
|
||||||
|
<Icons.Instagram />
|
||||||
|
</a>
|
||||||
|
<a href="#" className="text-neutral-600 hover:text-fuchsia-600 dark:text-neutral-400">
|
||||||
|
<Icons.Twitter />
|
||||||
|
</a>
|
||||||
|
<a href="#" className="text-neutral-600 hover:text-fuchsia-600 dark:text-neutral-400">
|
||||||
|
<Icons.LinkedIn />
|
||||||
|
</a>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
<h3 className="font-semibold">Get Involved</h3>
|
||||||
|
<ul className="mt-4 space-y-2 text-sm">
|
||||||
|
<li><a href="#/donate" className="text-neutral-600 hover:text-fuchsia-600 dark:text-neutral-400">Donate</a></li>
|
||||||
|
<li><a href="#/volunteers" className="text-neutral-600 hover:text-fuchsia-600 dark:text-neutral-400">Volunteer</a></li>
|
||||||
|
<li><a href="#/sponsors" className="text-neutral-600 hover:text-fuchsia-600 dark:text-neutral-400">Corporate Partnerships</a></li>
|
||||||
|
<li><a href="#/stories" className="text-neutral-600 hover:text-fuchsia-600 dark:text-neutral-400">Success Stories</a></li>
|
||||||
|
</ul>
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
<h3 className="font-semibold">Organization</h3>
|
||||||
|
<ul className="mt-4 space-y-2 text-sm">
|
||||||
|
<li><a href="#/testimonies" className="text-neutral-600 hover:text-fuchsia-600 dark:text-neutral-400">Testimonials</a></li>
|
||||||
|
<li><a href="#/legal" className="text-neutral-600 hover:text-fuchsia-600 dark:text-neutral-400">Legal & Policies</a></li>
|
||||||
|
<li><a href="mailto:contact@miraclesinmotion.org" className="text-neutral-600 hover:text-fuchsia-600 dark:text-neutral-400">Contact Us</a></li>
|
||||||
|
<li><a href="tel:+15551234567" className="text-neutral-600 hover:text-fuchsia-600 dark:text-neutral-400">(555) 123-4567</a></li>
|
||||||
|
</ul>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div className="mt-8 border-t border-white/30 pt-8 text-center text-xs text-neutral-500 dark:border-white/10 dark:text-neutral-400">
|
||||||
|
<p>© 2024 Miracles in Motion. All rights reserved. EIN: 12-3456789</p>
|
||||||
|
<p className="mt-1">501(c)(3) nonprofit organization. Donations are tax-deductible to the extent allowed by law.</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</footer>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
function StickyDonate() {
|
||||||
|
return (
|
||||||
|
<div className="fixed bottom-4 right-4 z-50 md:hidden">
|
||||||
|
<a
|
||||||
|
href="#/donate"
|
||||||
|
className="flex h-14 w-14 items-center justify-center rounded-full bg-gradient-to-br from-fuchsia-500 to-indigo-500 text-white shadow-lg shadow-fuchsia-500/25 transition hover:scale-105"
|
||||||
|
>
|
||||||
|
<Icons.Heart />
|
||||||
|
</a>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
function CookieBanner() {
|
||||||
|
const [show, setShow] = useState(true);
|
||||||
|
|
||||||
|
if (!show) return null;
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div className="fixed bottom-4 left-4 right-4 z-50 rounded-2xl border border-white/30 bg-white/90 p-4 shadow-xl backdrop-blur dark:border-white/10 dark:bg-black/90 md:max-w-md md:right-auto">
|
||||||
|
<p className="text-sm">
|
||||||
|
We use cookies to improve your experience. By continuing, you agree to our cookie policy.
|
||||||
|
</p>
|
||||||
|
<div className="mt-3 flex gap-2">
|
||||||
|
<button
|
||||||
|
onClick={() => setShow(false)}
|
||||||
|
className="btn-primary text-xs"
|
||||||
|
>
|
||||||
|
Accept
|
||||||
|
</button>
|
||||||
|
<button
|
||||||
|
onClick={() => setShow(false)}
|
||||||
|
className="btn-secondary text-xs"
|
||||||
|
>
|
||||||
|
Decline
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
function AnalyticsLoader() {
|
||||||
|
useEffect(() => {
|
||||||
|
// Load Google Analytics or other analytics here
|
||||||
|
// This is a placeholder for actual analytics implementation
|
||||||
|
}, []);
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
function Magnetic({ children }) {
|
||||||
|
return (
|
||||||
|
<div className="relative">
|
||||||
|
{children}
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Add missing icon components
|
||||||
|
const {
|
||||||
|
HandHeart, Users, Globe, Star, CheckCircle2, ArrowRight,
|
||||||
|
Heart, MapPin, Mail, Phone, Sparkles, FileText, Quote,
|
||||||
|
Moon, SunMedium, Backpack, Shirt, Building2, BookOpenText,
|
||||||
|
ShieldCheck
|
||||||
|
} = Icons;
|
||||||
|
|
||||||
|
// React DOM render
|
||||||
|
if (typeof ReactDOM !== 'undefined' && document.getElementById('root')) {
|
||||||
|
ReactDOM.render(React.createElement(MiraclesInMotionSite), document.getElementById('root'));
|
||||||
|
}
|
||||||
37
package.json
Normal file
37
package.json
Normal file
@@ -0,0 +1,37 @@
|
|||||||
|
{
|
||||||
|
"name": "miracles-in-motion-web",
|
||||||
|
"version": "1.0.0",
|
||||||
|
"description": "Public website for Miracles In Motion 501(c)3 non-profit organization",
|
||||||
|
"main": "index.html",
|
||||||
|
"scripts": {
|
||||||
|
"dev": "live-server --port=3000",
|
||||||
|
"build": "npm run copy-files",
|
||||||
|
"copy-files": "mkdir -p dist && cp -r *.html *.jsx *.css *.js *.json assets/ dist/",
|
||||||
|
"deploy": "npm run build && gh-pages -d dist"
|
||||||
|
},
|
||||||
|
"keywords": [
|
||||||
|
"non-profit",
|
||||||
|
"charity",
|
||||||
|
"501c3",
|
||||||
|
"miracles-in-motion",
|
||||||
|
"community",
|
||||||
|
"donations",
|
||||||
|
"volunteers"
|
||||||
|
],
|
||||||
|
"author": "Miracles In Motion",
|
||||||
|
"license": "MIT",
|
||||||
|
"repository": {
|
||||||
|
"type": "git",
|
||||||
|
"url": "https://github.com/Miracles-In-Motion/public-web.git"
|
||||||
|
},
|
||||||
|
"homepage": "https://miraclesinmotion.org",
|
||||||
|
"devDependencies": {
|
||||||
|
"live-server": "^1.2.2",
|
||||||
|
"gh-pages": "^5.0.0"
|
||||||
|
},
|
||||||
|
"dependencies": {
|
||||||
|
"react": "^18.2.0",
|
||||||
|
"react-dom": "^18.2.0",
|
||||||
|
"framer-motion": "^10.16.4"
|
||||||
|
}
|
||||||
|
}
|
||||||
373
styles.css
Normal file
373
styles.css
Normal file
@@ -0,0 +1,373 @@
|
|||||||
|
/* Miracles In Motion - Custom Styles */
|
||||||
|
|
||||||
|
/* Button Components */
|
||||||
|
.btn-primary {
|
||||||
|
display: inline-flex;
|
||||||
|
align-items: center;
|
||||||
|
gap: 0.5rem;
|
||||||
|
border-radius: 9999px;
|
||||||
|
background: linear-gradient(to right, #c026d3, #4f46e5);
|
||||||
|
padding: 0.75rem 1.5rem;
|
||||||
|
font-size: 0.875rem;
|
||||||
|
font-weight: 500;
|
||||||
|
color: white;
|
||||||
|
box-shadow: 0 10px 15px -3px rgba(236, 72, 153, 0.25);
|
||||||
|
transition: all 0.3s;
|
||||||
|
text-decoration: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
.btn-primary:hover {
|
||||||
|
transform: scale(1.05);
|
||||||
|
box-shadow: 0 25px 25px -5px rgba(0, 0, 0, 0.1);
|
||||||
|
}
|
||||||
|
|
||||||
|
.btn-secondary {
|
||||||
|
display: inline-flex;
|
||||||
|
align-items: center;
|
||||||
|
gap: 0.5rem;
|
||||||
|
border-radius: 9999px;
|
||||||
|
border: 1px solid rgba(212, 212, 216, 0.3);
|
||||||
|
background: rgba(255, 255, 255, 0.7);
|
||||||
|
backdrop-filter: blur(12px);
|
||||||
|
padding: 0.75rem 1.5rem;
|
||||||
|
font-size: 0.875rem;
|
||||||
|
font-weight: 500;
|
||||||
|
color: #374151;
|
||||||
|
transition: all 0.3s;
|
||||||
|
text-decoration: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
.btn-secondary:hover {
|
||||||
|
background: rgba(255, 255, 255, 1);
|
||||||
|
box-shadow: 0 10px 15px -3px rgba(0, 0, 0, 0.1);
|
||||||
|
}
|
||||||
|
|
||||||
|
.btn-white {
|
||||||
|
display: inline-flex;
|
||||||
|
align-items: center;
|
||||||
|
gap: 0.5rem;
|
||||||
|
border-radius: 9999px;
|
||||||
|
background: white;
|
||||||
|
padding: 0.75rem 1.5rem;
|
||||||
|
font-size: 0.875rem;
|
||||||
|
font-weight: 500;
|
||||||
|
color: #111827;
|
||||||
|
box-shadow: 0 10px 15px -3px rgba(0, 0, 0, 0.1);
|
||||||
|
transition: all 0.3s;
|
||||||
|
text-decoration: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
.btn-white:hover {
|
||||||
|
transform: scale(1.05);
|
||||||
|
box-shadow: 0 25px 25px -5px rgba(0, 0, 0, 0.1);
|
||||||
|
}
|
||||||
|
|
||||||
|
.navlink {
|
||||||
|
font-size: 0.875rem;
|
||||||
|
font-weight: 500;
|
||||||
|
color: #6b7280;
|
||||||
|
transition: color 0.3s;
|
||||||
|
text-decoration: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
.navlink:hover {
|
||||||
|
color: #ec4899;
|
||||||
|
}
|
||||||
|
|
||||||
|
.input {
|
||||||
|
width: 100%;
|
||||||
|
border-radius: 0.75rem;
|
||||||
|
border: 1px solid rgba(255, 255, 255, 0.3);
|
||||||
|
background: rgba(255, 255, 255, 0.7);
|
||||||
|
backdrop-filter: blur(12px);
|
||||||
|
padding: 0.5rem 0.75rem;
|
||||||
|
font-size: 0.875rem;
|
||||||
|
transition: all 0.3s;
|
||||||
|
}
|
||||||
|
|
||||||
|
.input:focus {
|
||||||
|
outline: none;
|
||||||
|
border-color: #ec4899;
|
||||||
|
box-shadow: 0 0 0 3px rgba(236, 72, 153, 0.2);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Custom Animations */
|
||||||
|
@keyframes marquee {
|
||||||
|
0% { transform: translateX(100%); }
|
||||||
|
100% { transform: translateX(-100%); }
|
||||||
|
}
|
||||||
|
|
||||||
|
.animate-marquee {
|
||||||
|
animation: marquee 30s linear infinite;
|
||||||
|
}
|
||||||
|
|
||||||
|
@keyframes float {
|
||||||
|
0%, 100% { transform: translateY(0px); }
|
||||||
|
50% { transform: translateY(-10px); }
|
||||||
|
}
|
||||||
|
|
||||||
|
.animate-float {
|
||||||
|
animation: float 6s ease-in-out infinite;
|
||||||
|
}
|
||||||
|
|
||||||
|
@keyframes pulse-slow {
|
||||||
|
0%, 100% { opacity: 1; }
|
||||||
|
50% { opacity: 0.5; }
|
||||||
|
}
|
||||||
|
|
||||||
|
.animate-pulse-slow {
|
||||||
|
animation: pulse-slow 4s cubic-bezier(0.4, 0, 0.6, 1) infinite;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Gradient Text */
|
||||||
|
.gradient-text {
|
||||||
|
background: linear-gradient(135deg, #ec4899, #8b5cf6, #3b82f6);
|
||||||
|
-webkit-background-clip: text;
|
||||||
|
-webkit-text-fill-color: transparent;
|
||||||
|
background-clip: text;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Hero Background Pattern */
|
||||||
|
.hero-pattern {
|
||||||
|
background-image:
|
||||||
|
radial-gradient(circle at 20% 80%, rgba(120, 119, 198, 0.3) 0%, transparent 50%),
|
||||||
|
radial-gradient(circle at 80% 20%, rgba(255, 119, 198, 0.3) 0%, transparent 50%),
|
||||||
|
radial-gradient(circle at 40% 40%, rgba(236, 72, 153, 0.2) 0%, transparent 50%);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Card Hover Effects */
|
||||||
|
.card-hover {
|
||||||
|
transition: all 0.3s cubic-bezier(0.4, 0, 0.2, 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
.card-hover:hover {
|
||||||
|
transform: translateY(-4px);
|
||||||
|
box-shadow: 0 20px 40px rgba(0, 0, 0, 0.1);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Custom Scrollbar */
|
||||||
|
::-webkit-scrollbar {
|
||||||
|
width: 8px;
|
||||||
|
}
|
||||||
|
|
||||||
|
::-webkit-scrollbar-track {
|
||||||
|
background: rgba(255, 255, 255, 0.1);
|
||||||
|
border-radius: 4px;
|
||||||
|
}
|
||||||
|
|
||||||
|
::-webkit-scrollbar-thumb {
|
||||||
|
background: linear-gradient(135deg, #ec4899, #8b5cf6);
|
||||||
|
border-radius: 4px;
|
||||||
|
}
|
||||||
|
|
||||||
|
::-webkit-scrollbar-thumb:hover {
|
||||||
|
background: linear-gradient(135deg, #db2777, #7c3aed);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Focus Styles for Accessibility */
|
||||||
|
.focus-visible\:ring-2:focus-visible {
|
||||||
|
outline: 2px solid transparent;
|
||||||
|
outline-offset: 2px;
|
||||||
|
box-shadow: 0 0 0 2px rgba(236, 72, 153, 0.5);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Screen Reader Only */
|
||||||
|
.sr-only {
|
||||||
|
position: absolute;
|
||||||
|
width: 1px;
|
||||||
|
height: 1px;
|
||||||
|
padding: 0;
|
||||||
|
margin: -1px;
|
||||||
|
overflow: hidden;
|
||||||
|
clip: rect(0, 0, 0, 0);
|
||||||
|
white-space: nowrap;
|
||||||
|
border: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.focus\:not-sr-only:focus {
|
||||||
|
position: static;
|
||||||
|
width: auto;
|
||||||
|
height: auto;
|
||||||
|
padding: inherit;
|
||||||
|
margin: inherit;
|
||||||
|
overflow: visible;
|
||||||
|
clip: auto;
|
||||||
|
white-space: normal;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Print Styles */
|
||||||
|
@media print {
|
||||||
|
.no-print {
|
||||||
|
display: none !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
body {
|
||||||
|
color: black !important;
|
||||||
|
background: white !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
.gradient-text {
|
||||||
|
color: black !important;
|
||||||
|
-webkit-text-fill-color: initial !important;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* High Contrast Mode Support */
|
||||||
|
@media (prefers-contrast: high) {
|
||||||
|
.btn-primary {
|
||||||
|
border: 2px solid;
|
||||||
|
}
|
||||||
|
|
||||||
|
.btn-secondary {
|
||||||
|
border: 2px solid;
|
||||||
|
}
|
||||||
|
|
||||||
|
.card-hover {
|
||||||
|
border: 2px solid;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Reduced Motion Support */
|
||||||
|
@media (prefers-reduced-motion: reduce) {
|
||||||
|
*,
|
||||||
|
*::before,
|
||||||
|
*::after {
|
||||||
|
animation-duration: 0.01ms !important;
|
||||||
|
animation-iteration-count: 1 !important;
|
||||||
|
transition-duration: 0.01ms !important;
|
||||||
|
scroll-behavior: auto !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
.animate-marquee {
|
||||||
|
animation: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
.animate-float {
|
||||||
|
animation: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
.animate-pulse-slow {
|
||||||
|
animation: none;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Dark Mode Adjustments */
|
||||||
|
@media (prefers-color-scheme: dark) {
|
||||||
|
:root {
|
||||||
|
color-scheme: dark;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Mobile Optimizations */
|
||||||
|
@media (max-width: 640px) {
|
||||||
|
.btn-primary,
|
||||||
|
.btn-secondary {
|
||||||
|
padding: 0.5rem 1rem;
|
||||||
|
font-size: 0.75rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.hero-pattern {
|
||||||
|
background-image: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
.animate-marquee {
|
||||||
|
animation-duration: 20s;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Tablet Optimizations */
|
||||||
|
@media (min-width: 641px) and (max-width: 1024px) {
|
||||||
|
.card-hover:hover {
|
||||||
|
transform: translateY(-2px);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Loading States */
|
||||||
|
.loading {
|
||||||
|
opacity: 0.6;
|
||||||
|
pointer-events: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
.skeleton {
|
||||||
|
background: linear-gradient(90deg,
|
||||||
|
rgba(255, 255, 255, 0.1) 25%,
|
||||||
|
rgba(255, 255, 255, 0.2) 50%,
|
||||||
|
rgba(255, 255, 255, 0.1) 75%
|
||||||
|
);
|
||||||
|
background-size: 200% 100%;
|
||||||
|
animation: skeleton-loading 1.5s infinite;
|
||||||
|
}
|
||||||
|
|
||||||
|
@keyframes skeleton-loading {
|
||||||
|
0% { background-position: 200% 0; }
|
||||||
|
100% { background-position: -200% 0; }
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Form Validation States */
|
||||||
|
.input:invalid {
|
||||||
|
border-color: #ef4444;
|
||||||
|
}
|
||||||
|
|
||||||
|
.input:invalid:focus {
|
||||||
|
border-color: #ef4444;
|
||||||
|
box-shadow: 0 0 0 3px rgba(239, 68, 68, 0.2);
|
||||||
|
}
|
||||||
|
|
||||||
|
.input:valid {
|
||||||
|
border-color: #10b981;
|
||||||
|
}
|
||||||
|
|
||||||
|
.input:valid:focus {
|
||||||
|
border-color: #10b981;
|
||||||
|
box-shadow: 0 0 0 3px rgba(16, 185, 129, 0.2);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Utility Classes */
|
||||||
|
.text-balance {
|
||||||
|
text-wrap: balance;
|
||||||
|
}
|
||||||
|
|
||||||
|
.bg-noise {
|
||||||
|
background-image:
|
||||||
|
url("data:image/svg+xml,%3Csvg viewBox='0 0 256 256' xmlns='http://www.w3.org/2000/svg'%3E%3Cfilter id='noiseFilter'%3E%3CfeTurbulence type='fractalNoise' baseFrequency='0.65' numOctaves='4' stitchTiles='stitch'/%3E%3C/filter%3E%3Crect width='100%25' height='100%25' filter='url(%23noiseFilter)' opacity='0.05'/%3E%3C/svg%3E");
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Error and Success States */
|
||||||
|
.error-state {
|
||||||
|
border-color: #ef4444;
|
||||||
|
background-color: #fef2f2;
|
||||||
|
color: #b91c1c;
|
||||||
|
}
|
||||||
|
|
||||||
|
.success-state {
|
||||||
|
border-color: #10b981;
|
||||||
|
background-color: #f0fdf4;
|
||||||
|
color: #166534;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Performance Optimizations */
|
||||||
|
.will-change-transform {
|
||||||
|
will-change: transform;
|
||||||
|
}
|
||||||
|
|
||||||
|
.contain-layout {
|
||||||
|
contain: layout;
|
||||||
|
}
|
||||||
|
|
||||||
|
.contain-paint {
|
||||||
|
contain: paint;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Component-specific styles */
|
||||||
|
.logo-glow {
|
||||||
|
filter: drop-shadow(0 0 10px rgba(236, 72, 153, 0.3));
|
||||||
|
}
|
||||||
|
|
||||||
|
.text-shadow {
|
||||||
|
text-shadow: 0 2px 4px rgba(0, 0, 0, 0.1);
|
||||||
|
}
|
||||||
|
|
||||||
|
.backdrop-blur-glass {
|
||||||
|
backdrop-filter: blur(12px);
|
||||||
|
-webkit-backdrop-filter: blur(12px);
|
||||||
|
}
|
||||||
30
vite.config.ts
Normal file
30
vite.config.ts
Normal file
@@ -0,0 +1,30 @@
|
|||||||
|
import { defineConfig } from 'vite'
|
||||||
|
import react from '@vitejs/plugin-react'
|
||||||
|
import { resolve } from 'path'
|
||||||
|
|
||||||
|
// https://vitejs.dev/config/
|
||||||
|
export default defineConfig({
|
||||||
|
plugins: [react()],
|
||||||
|
resolve: {
|
||||||
|
alias: {
|
||||||
|
'@': resolve(__dirname, './src'),
|
||||||
|
},
|
||||||
|
},
|
||||||
|
server: {
|
||||||
|
port: 3000,
|
||||||
|
open: true,
|
||||||
|
},
|
||||||
|
build: {
|
||||||
|
outDir: 'dist',
|
||||||
|
sourcemap: true,
|
||||||
|
rollupOptions: {
|
||||||
|
output: {
|
||||||
|
manualChunks: {
|
||||||
|
vendor: ['react', 'react-dom'],
|
||||||
|
motion: ['framer-motion'],
|
||||||
|
icons: ['lucide-react'],
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
})
|
||||||
Reference in New Issue
Block a user