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:
defiQUG
2025-10-04 17:46:58 -07:00
parent 7c3fe21dfb
commit 0933c8208c
10 changed files with 1300 additions and 42 deletions

190
CONTRIBUTING.md Normal file
View 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
View 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

BIN
README.md

Binary file not shown.

153
SECURITY.md Normal file
View 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
View 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
View 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>

View File

@@ -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
View 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
View 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
View 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'],
},
},
},
},
})