diff --git a/README.md b/README.md new file mode 100644 index 0000000..7692da9 --- /dev/null +++ b/README.md @@ -0,0 +1,117 @@ +# Contact Information Form + +A responsive HTML form for collecting user's name and mobile number with real-time validation and modern styling. + +## Features + +### Form Fields +- **Full Name**: Text input with validation (2-50 characters, letters and spaces only) +- **Mobile Number**: Tel input with validation (10-15 digits, optional international format) + +### Validation +- **Real-time validation**: Instant feedback as user types +- **Pattern matching**: Name must contain only letters and spaces +- **Mobile format**: Accepts 10-15 digit numbers with optional + prefix +- **Auto-formatting**: Mobile number gets formatted for better readability +- **Submit prevention**: Button disabled until all fields are valid + +### Design Features +- **Responsive design**: Works on desktop, tablet, and mobile devices +- **Modern styling**: Gradient backgrounds, smooth animations, and hover effects +- **Accessibility**: Proper labels, focus states, and error messages +- **User feedback**: Success messages and loading states + +## Files + +- `contact-form.html` - Main form HTML structure +- `form-style.css` - Complete CSS styling with responsive design +- `form-script.js` - JavaScript for validation and user interactions +- `test-form.html` - Test suite for validation functions + +## Usage + +1. Open `contact-form.html` in a web browser +2. Fill in your full name and mobile number +3. The form will validate inputs in real-time +4. Submit button becomes active when all fields are valid +5. Click Submit to see the success message + +## Testing + +Open `test-form.html` to run automated tests for the validation functions. The test suite validates: + +### Name Validation Tests +- ✅ Valid names with letters and spaces +- ✅ Rejects names with numbers or special characters +- ✅ Enforces length requirements (2-50 characters) + +### Mobile Validation Tests +- ✅ Accepts 10-15 digit numbers +- ✅ Supports international format with + prefix +- ✅ Handles formatted numbers with spaces +- ✅ Rejects invalid formats and lengths + +## Browser Compatibility + +- Chrome, Firefox, Safari, Edge (modern versions) +- Mobile browsers (iOS Safari, Android Chrome) +- Responsive design works on all screen sizes + +## Customization + +### Styling +Edit `form-style.css` to customize: +- Colors and gradients +- Font sizes and families +- Spacing and layout +- Animation effects + +### Validation Rules +Edit `form-script.js` to modify: +- Name validation pattern +- Mobile number format requirements +- Error messages +- Form behavior + +### Form Submission +The current implementation shows a success message. To integrate with a backend: + +```javascript +// Replace the setTimeout in form submission with actual API call +fetch('/api/submit-contact', { + method: 'POST', + headers: { + 'Content-Type': 'application/json', + }, + body: JSON.stringify({ + name: name, + mobile: mobile + }) +}) +.then(response => response.json()) +.then(data => { + // Handle success +}) +.catch(error => { + // Handle error +}); +``` + +## Security Considerations + +- Client-side validation only - always validate on the server side +- Sanitize inputs before processing +- Consider rate limiting for form submissions +- Implement CSRF protection for production use + +## Accessibility Features + +- Semantic HTML structure +- Proper form labels and associations +- Focus indicators and keyboard navigation +- Error messages linked to form fields +- High contrast colors for readability + +--- + +**Note**: This is a client-side only implementation. For production use, add server-side validation and proper data handling. diff --git a/USER_FORM_DOCUMENTATION.md b/USER_FORM_DOCUMENTATION.md new file mode 100644 index 0000000..33e400a --- /dev/null +++ b/USER_FORM_DOCUMENTATION.md @@ -0,0 +1,102 @@ +# Angular User Form - Name and Email + +This project demonstrates a clean, professional Angular reactive form that collects user name and email information with proper validation. + +## Features + +- **Reactive Forms**: Built using Angular's ReactiveFormsModule for better form control and validation +- **Form Validation**: Comprehensive validation including: + - Required field validation for both name and email + - Email format validation + - Name length validation (2-50 characters) + - Name pattern validation (letters and spaces only) +- **User Experience**: + - Real-time validation feedback + - Visual error states with helpful error messages + - Responsive design that works on all screen sizes + - Loading and success states + - Clean, modern UI with smooth animations +- **Accessibility**: Form labels, proper input types, and keyboard navigation support + +## Files Structure + +``` +src/app/ +├── user-form.component.ts # Component logic and form handling +├── user-form.component.html # Form template with validation +├── user-form.component.css # Styling and responsive design +└── app.module.ts # Module configuration with imports +``` + +## Component Details + +### UserFormComponent + +**Key Features:** +- Uses Angular FormBuilder for reactive form creation +- Implements comprehensive validation rules +- Provides helper methods for error checking and display +- Handles form submission with success feedback +- Includes form reset functionality + +**Validation Rules:** +- **Name**: Required, 2-50 characters, letters and spaces only +- **Email**: Required, valid email format, max 100 characters + +### Form Template + +**UI Elements:** +- Clean, card-based layout +- Visual feedback for form states (valid/invalid/touched) +- Error messages with icons +- Submit and Reset buttons with appropriate states +- Development status display for debugging + +### Styling + +**Design Features:** +- Modern gradient background +- Card-based form layout with shadow effects +- Smooth hover and focus transitions +- Responsive design for mobile and desktop +- Error state styling with animations +- Professional color scheme + +## Usage + +1. **Import the component** in your app.module.ts: +```typescript +import { UserFormComponent } from './user-form.component'; + +@NgModule({ + declarations: [ + // ... other components + UserFormComponent + ], + // ... rest of module config +}) +``` + +2. **Use in templates**: +```html + +``` + +## Form Behavior + +- **Validation**: Real-time validation with visual feedback +- **Submission**: Form submits only when all fields are valid +- **Reset**: Users can reset the form to clear all data +- **Error Display**: Context-aware error messages guide users to correct issues + +## Customization + +The form can be easily customized by modifying: +- Validation rules in `user-form.component.ts` +- Styling in `user-form.component.css` +- Form layout in `user-form.component.html` + +## Dependencies + +- Angular (with ReactiveFormsModule) +- No external UI libraries required - uses pure CSS for styling diff --git a/about-us-style.css b/about-us-style.css new file mode 100644 index 0000000..3f65edb --- /dev/null +++ b/about-us-style.css @@ -0,0 +1,490 @@ +/* Reset and base styles */ +* { + margin: 0; + padding: 0; + box-sizing: border-box; +} + +body { + font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif; + line-height: 1.6; + color: #333; + overflow-x: hidden; +} + +.container { + max-width: 1200px; + margin: 0 auto; + padding: 0 20px; +} + +/* Navigation */ +.navbar { + background: rgba(255, 255, 255, 0.98); + box-shadow: 0 2px 10px rgba(0, 0, 0, 0.1); + position: fixed; + width: 100%; + top: 0; + z-index: 1000; + backdrop-filter: blur(10px); +} + +.nav-container { + max-width: 1200px; + margin: 0 auto; + padding: 0 20px; + display: flex; + justify-content: space-between; + align-items: center; + height: 70px; +} + +.logo { + font-size: 1.5rem; + font-weight: 700; + background: linear-gradient(135deg, #667eea 0%, #764ba2 100%); + -webkit-background-clip: text; + -webkit-text-fill-color: transparent; + background-clip: text; +} + +.nav-links { + display: flex; + list-style: none; + gap: 30px; +} + +.nav-links a { + text-decoration: none; + color: #333; + font-weight: 500; + transition: color 0.3s ease; + position: relative; +} + +.nav-links a:hover, +.nav-links a.active { + color: #667eea; +} + +.nav-links a::after { + content: ''; + position: absolute; + bottom: -5px; + left: 0; + width: 0; + height: 2px; + background: linear-gradient(135deg, #667eea 0%, #764ba2 100%); + transition: width 0.3s ease; +} + +.nav-links a:hover::after, +.nav-links a.active::after { + width: 100%; +} + +/* Hero Section */ +.hero-section { + height: 500px; + background: linear-gradient(135deg, #667eea 0%, #764ba2 100%); + position: relative; + display: flex; + align-items: center; + justify-content: center; + margin-top: 70px; + overflow: hidden; +} + +.hero-section::before { + content: ''; + position: absolute; + top: 0; + left: 0; + right: 0; + bottom: 0; + background-image: url('https://images.unsplash.com/photo-1497366216548-37526070297c?w=1600&h=900&fit=crop'); + background-size: cover; + background-position: center; + opacity: 0.2; +} + +.hero-overlay { + position: absolute; + top: 0; + left: 0; + right: 0; + bottom: 0; + background: linear-gradient(135deg, rgba(102, 126, 234, 0.9) 0%, rgba(118, 75, 162, 0.9) 100%); +} + +.hero-content { + position: relative; + z-index: 1; + text-align: center; + color: white; +} + +.hero-title { + font-size: 4rem; + font-weight: 700; + margin-bottom: 20px; + animation: fadeInUp 1s ease; +} + +.hero-subtitle { + font-size: 1.5rem; + font-weight: 300; + animation: fadeInUp 1s ease 0.2s backwards; +} + +@keyframes fadeInUp { + from { + opacity: 0; + transform: translateY(30px); + } + to { + opacity: 1; + transform: translateY(0); + } +} + +/* Story Section */ +.story-section { + padding: 100px 0; + background: #fff; +} + +.story-content { + display: grid; + grid-template-columns: 1fr 1fr; + gap: 60px; + align-items: center; +} + +.story-text h2 { + font-size: 2.5rem; + margin-bottom: 30px; + color: #333; + position: relative; + padding-bottom: 15px; +} + +.story-text h2::after { + content: ''; + position: absolute; + bottom: 0; + left: 0; + width: 60px; + height: 4px; + background: linear-gradient(135deg, #667eea 0%, #764ba2 100%); + border-radius: 2px; +} + +.story-text p { + font-size: 1.1rem; + line-height: 1.8; + color: #555; + margin-bottom: 20px; +} + +.story-image { + border-radius: 15px; + overflow: hidden; + box-shadow: 0 20px 60px rgba(0, 0, 0, 0.15); + transform: perspective(1000px) rotateY(-5deg); + transition: transform 0.5s ease; +} + +.story-image:hover { + transform: perspective(1000px) rotateY(0deg); +} + +.story-image img { + width: 100%; + height: 100%; + object-fit: cover; + display: block; +} + +/* Mission Section */ +.mission-section { + padding: 100px 0; + background: linear-gradient(135deg, #f8f9ff 0%, #f0f2ff 100%); +} + +.section-title { + text-align: center; + font-size: 2.5rem; + margin-bottom: 60px; + color: #333; +} + +.mission-grid { + display: grid; + grid-template-columns: repeat(3, 1fr); + gap: 40px; +} + +.mission-card { + background: white; + padding: 40px 30px; + border-radius: 15px; + text-align: center; + box-shadow: 0 10px 30px rgba(0, 0, 0, 0.08); + transition: transform 0.3s ease, box-shadow 0.3s ease; +} + +.mission-card:hover { + transform: translateY(-10px); + box-shadow: 0 20px 50px rgba(102, 126, 234, 0.2); +} + +.mission-icon { + font-size: 3rem; + margin-bottom: 20px; +} + +.mission-card h3 { + font-size: 1.5rem; + margin-bottom: 15px; + color: #333; +} + +.mission-card p { + color: #666; + line-height: 1.8; +} + +/* Team Section */ +.team-section { + padding: 100px 0; + background: white; +} + +.section-subtitle { + text-align: center; + font-size: 1.2rem; + color: #666; + margin-top: -40px; + margin-bottom: 60px; +} + +.team-grid { + display: grid; + grid-template-columns: repeat(4, 1fr); + gap: 40px; +} + +.team-member { + text-align: center; + transition: transform 0.3s ease; +} + +.team-member:hover { + transform: translateY(-10px); +} + +.member-image { + width: 200px; + height: 200px; + margin: 0 auto 20px; + border-radius: 50%; + overflow: hidden; + border: 5px solid #f0f2ff; + box-shadow: 0 10px 30px rgba(0, 0, 0, 0.1); + transition: border-color 0.3s ease; +} + +.team-member:hover .member-image { + border-color: #667eea; +} + +.member-image img { + width: 100%; + height: 100%; + object-fit: cover; +} + +.team-member h3 { + font-size: 1.3rem; + margin-bottom: 5px; + color: #333; +} + +.member-role { + color: #667eea; + font-weight: 600; + margin-bottom: 10px; +} + +.member-bio { + color: #666; + font-size: 0.95rem; + line-height: 1.6; +} + +/* Stats Section */ +.stats-section { + padding: 80px 0; + background: linear-gradient(135deg, #667eea 0%, #764ba2 100%); + color: white; +} + +.stats-grid { + display: grid; + grid-template-columns: repeat(4, 1fr); + gap: 40px; +} + +.stat-item { + text-align: center; +} + +.stat-number { + font-size: 3rem; + font-weight: 700; + margin-bottom: 10px; +} + +.stat-label { + font-size: 1.1rem; + opacity: 0.9; +} + +/* CTA Section */ +.cta-section { + padding: 100px 0; + background: white; + text-align: center; +} + +.cta-section h2 { + font-size: 2.5rem; + margin-bottom: 20px; + color: #333; +} + +.cta-section p { + font-size: 1.2rem; + color: #666; + margin-bottom: 40px; +} + +.cta-button { + display: inline-block; + padding: 18px 50px; + background: linear-gradient(135deg, #667eea 0%, #764ba2 100%); + color: white; + text-decoration: none; + border-radius: 50px; + font-size: 1.1rem; + font-weight: 600; + transition: transform 0.3s ease, box-shadow 0.3s ease; + box-shadow: 0 10px 30px rgba(102, 126, 234, 0.3); +} + +.cta-button:hover { + transform: translateY(-3px); + box-shadow: 0 15px 40px rgba(102, 126, 234, 0.4); +} + +/* Footer */ +.footer { + background: #2d3748; + color: white; + padding: 30px 0; + text-align: center; +} + +.footer p { + margin: 0; +} + +/* Responsive Design */ +@media (max-width: 1024px) { + .team-grid { + grid-template-columns: repeat(2, 1fr); + } + + .stats-grid { + grid-template-columns: repeat(2, 1fr); + } +} + +@media (max-width: 768px) { + .nav-links { + gap: 15px; + } + + .hero-title { + font-size: 2.5rem; + } + + .hero-subtitle { + font-size: 1.2rem; + } + + .story-content { + grid-template-columns: 1fr; + gap: 40px; + } + + .story-image { + transform: none; + } + + .mission-grid { + grid-template-columns: 1fr; + } + + .team-grid { + grid-template-columns: 1fr; + } + + .stats-grid { + grid-template-columns: 1fr; + gap: 30px; + } + + .section-title { + font-size: 2rem; + } +} + +@media (max-width: 480px) { + .nav-container { + flex-direction: column; + height: auto; + padding: 15px 20px; + } + + .nav-links { + margin-top: 10px; + } + + .hero-section { + height: 400px; + margin-top: 100px; + } + + .hero-title { + font-size: 2rem; + } + + .hero-subtitle { + font-size: 1rem; + } + + .story-section, + .mission-section, + .team-section, + .cta-section { + padding: 60px 0; + } + + .story-text h2, + .section-title, + .cta-section h2 { + font-size: 1.8rem; + } +} diff --git a/about-us.html b/about-us.html new file mode 100644 index 0000000..86e6784 --- /dev/null +++ b/about-us.html @@ -0,0 +1,145 @@ + + + + + + About Us - Our Story + + + + + +
+
+
+

About Us

+

Innovating the future, one step at a time

+
+
+ +
+
+
+
+

Our Story

+

Founded in 2020, we started with a simple mission: to create innovative solutions that make a difference in people's lives. What began as a small team of passionate individuals has grown into a thriving company dedicated to excellence and innovation.

+

Our journey has been marked by continuous learning, adaptation, and a commitment to delivering exceptional value to our customers. We believe in the power of technology to transform businesses and improve lives.

+
+
+ Team collaboration +
+
+
+
+ +
+
+

Our Mission & Vision

+
+
+
🎯
+

Our Mission

+

To empower businesses and individuals through innovative technology solutions that drive growth and success.

+
+
+
🔭
+

Our Vision

+

To be the leading provider of transformative solutions that shape the future of technology and business.

+
+
+
💎
+

Our Values

+

Innovation, integrity, excellence, and customer-centricity guide everything we do.

+
+
+
+
+ +
+
+

Meet Our Team

+

The talented people behind our success

+
+
+
+ Team member +
+

John Anderson

+

CEO & Founder

+

Visionary leader with 15+ years of experience in tech innovation.

+
+
+
+ Team member +
+

Sarah Mitchell

+

CTO

+

Technology expert passionate about building scalable solutions.

+
+
+
+ Team member +
+

Michael Chen

+

Head of Design

+

Creative designer focused on user-centered experiences.

+
+
+
+ Team member +
+

Emily Rodriguez

+

Marketing Director

+

Strategic marketer with a passion for brand storytelling.

+
+
+
+
+ +
+
+
+
+
500+
+
Happy Clients
+
+
+
1000+
+
Projects Completed
+
+
+
50+
+
Team Members
+
+
+
15+
+
Awards Won
+
+
+
+
+ +
+
+

Ready to Work With Us?

+

Let's create something amazing together

+ Get In Touch +
+
+ + + + diff --git a/about.html b/about.html new file mode 100644 index 0000000..de8c17b --- /dev/null +++ b/about.html @@ -0,0 +1,875 @@ + + + + + + About Us | Your Digital Journey Starts Here + + + + + + + + + + + +
+
+

About Our Story

+

Discover the passion, innovation, and dedication that drives us to create exceptional digital experiences for our users worldwide.

+
+
+ + +
+
+

Our Mission

+

Empowering businesses and individuals through innovative digital solutions

+ +
+
+

Building Tomorrow's Digital Experience

+

+ We believe in the transformative power of technology. Our mission is to create digital solutions that don't just meet today's needs, but anticipate tomorrow's opportunities. We're committed to bridging the gap between complex technology and intuitive user experiences. +

+

+ Every line of code we write, every design we craft, and every solution we deliver is guided by our commitment to excellence, innovation, and user satisfaction. We don't just build products; we create experiences that matter. +

+

+ Our approach combines cutting-edge technology with human-centered design, ensuring that our solutions are not only powerful and efficient but also accessible and enjoyable to use. +

+
+
+
🚀
+
+
+
+
+ + +
+
+

Our Values

+

The principles that guide everything we do

+ +
+
+
💡
+

Innovation

+

We embrace new ideas and cutting-edge technologies to deliver solutions that push boundaries and exceed expectations.

+
+ +
+
🤝
+

Collaboration

+

We believe in the power of teamwork, both within our organization and with our clients, to achieve extraordinary results.

+
+ +
+
🎯
+

Excellence

+

We're committed to delivering the highest quality in everything we do, from code to customer service.

+
+ +
+
🌍
+

Impact

+

We strive to create solutions that make a positive difference in the lives of our users and the broader community.

+
+ +
+
🔍
+

Transparency

+

We believe in open communication, honest feedback, and clear processes in all our interactions.

+
+ +
+
+

Agility

+

We adapt quickly to change, embrace new challenges, and continuously evolve to meet our users' needs.

+
+
+
+
+ + +
+
+

Meet Our Team

+

The passionate individuals behind our success

+ +
+
+
👨‍💻
+
+

Alex Johnson

+
CEO & Co-Founder
+

Visionary leader with 15+ years in tech, passionate about creating products that make a difference.

+
+
+ +
+
👩‍💻
+
+

Sarah Chen

+
CTO & Co-Founder
+

Technical innovator dedicated to building scalable, secure, and beautiful digital solutions.

+
+
+ +
+
👨‍🎨
+
+

Marcus Rodriguez

+
Head of Design
+

Creative director focused on crafting intuitive user experiences that delight and inspire.

+
+
+ +
+
👩‍💼
+
+

Emily Davis

+
VP of Operations
+

Operations expert ensuring smooth processes and exceptional customer experiences.

+
+
+
+
+
+ + +
+
+

Our Story

+

From a simple idea to a trusted digital partner

+ +
+

+ It all started in 2018 when our founders, Alex and Sarah, recognized a gap in the market for truly user-centered digital solutions. Working from a small office with just a handful of team members, they set out to create technology that would not only solve problems but also inspire and empower users. +

+ +

+ What began as late-night coding sessions and endless cups of coffee has evolved into a thriving company that serves thousands of users across 150+ countries. Our journey hasn't always been smooth, but every challenge has taught us valuable lessons and made us stronger. +

+ +
+

Today, We're Proud to Serve

+

50,000+ happy users worldwide, with 99.9% uptime and 24/7 support, making digital dreams a reality every day.

+
+ +

+ As we look to the future, we remain committed to our core mission: creating digital experiences that matter. We're constantly innovating, expanding our team with passionate individuals, and building solutions that will shape the future of digital interaction. +

+ +

+ Our story is still being written, and we're excited to have you be a part of it. Whether you're a user, a partner, or someone considering joining our team, you're contributing to something bigger than just software – you're helping us build the future. +

+
+
+
+ + +
+
+

Ready to Be Part of Our Story?

+

Join thousands of users who trust us to deliver exceptional digital experiences.

+ Get Started Today +
+
+ + + + + + + diff --git a/button-page.html b/button-page.html new file mode 100644 index 0000000..3625468 --- /dev/null +++ b/button-page.html @@ -0,0 +1,76 @@ + + + + + + Button Page + + + +
+

Welcome to the Button Page

+

Here's your small button:

+ +

+
+ + + + diff --git a/contact-form.html b/contact-form.html new file mode 100644 index 0000000..95af42c --- /dev/null +++ b/contact-form.html @@ -0,0 +1,51 @@ + + + + + + Contact Information Form + + + +
+

Contact Information Form

+ +
+
+ + + +
+ +
+ + + +
+ + + + +
+
+
+ + + + diff --git a/contact.html b/contact.html new file mode 100644 index 0000000..948a9d0 --- /dev/null +++ b/contact.html @@ -0,0 +1,1183 @@ + + + + + + Contact Us | YourBrand - Get in Touch + + + + + + + + + + + + + + +
+
+
+ +
+

Get in Touch

+

Ready to start your journey with us? Contact our friendly team - we're here to help you every step of the way.

+ +
+
+
📍
+
+

Visit Our Office

+

123 Innovation Street
+ Tech City, TC 12345
+ United States

+
+
+ +
+
📞
+
+

Call Us

+

Main: +1 (555) 123-4567
+ Support: +1 (555) 123-4568
+ Sales: +1 (555) 123-4569

+
+
+ +
+
✉️
+
+

Email Us

+

General: hello@yourbrand.com
+ Support: support@yourbrand.com
+ Sales: sales@yourbrand.com

+
+
+ +
+
💬
+
+

Live Chat

+

Available 24/7 on our website
+ Average response time: < 2 minutes
+ Start Live Chat

+
+
+
+ + +
+

Business Hours

+
+
+ Monday + 9:00 AM - 6:00 PM +
+
+ Tuesday + 9:00 AM - 6:00 PM +
+
+ Wednesday + 9:00 AM - 6:00 PM +
+
+ Thursday + 9:00 AM - 6:00 PM +
+
+ Friday + 9:00 AM - 5:00 PM +
+
+ Saturday + 10:00 AM - 2:00 PM +
+
+ Sunday + Closed +
+
+
+
+ + +
+

Send us a Message

+
+
+
+ + + +
+ +
+ + + +
+
+ +
+
+ + + +
+ +
+ + + +
+
+ +
+
+ + +
+ +
+ + + +
+
+ +
+ + + +
+ + + + +
+
+
+
+
+ + +
+
+

Follow Us

+

Stay connected with us on social media for the latest updates, tips, and behind-the-scenes content.

+ + +
+
+ + +
+
+

Find Us

+

Located in the heart of Tech City, we're easy to reach by car, public transportation, or on foot.

+ +
+
+ 🗺️ Interactive Map
+ 123 Innovation Street, Tech City, TC 12345
+ Click to open in Maps app +
+
+
+
+ + + + + + + diff --git a/form-script.js b/form-script.js new file mode 100644 index 0000000..8088895 --- /dev/null +++ b/form-script.js @@ -0,0 +1,190 @@ +// Contact Form JavaScript +document.addEventListener('DOMContentLoaded', function() { + const form = document.getElementById('contactForm'); + const nameInput = document.getElementById('fullName'); + const mobileInput = document.getElementById('mobileNumber'); + const nameError = document.getElementById('nameError'); + const mobileError = document.getElementById('mobileError'); + const successMessage = document.getElementById('successMessage'); + const submitBtn = form.querySelector('.submit-btn'); + + // Real-time validation functions + function validateName(name) { + const nameRegex = /^[a-zA-Z\s]{2,50}$/; + return nameRegex.test(name.trim()); + } + + function validateMobile(mobile) { + const mobileRegex = /^[\+]?[0-9]{10,15}$/; + return mobileRegex.test(mobile.replace(/\s/g, '')); + } + + function showError(element, message) { + element.textContent = message; + element.style.display = 'block'; + } + + function hideError(element) { + element.textContent = ''; + element.style.display = 'none'; + } + + function updateSubmitButton() { + const isNameValid = validateName(nameInput.value); + const isMobileValid = validateMobile(mobileInput.value); + + submitBtn.disabled = !(isNameValid && isMobileValid && nameInput.value.trim() && mobileInput.value.trim()); + } + + // Real-time name validation + nameInput.addEventListener('input', function() { + const name = this.value.trim(); + + if (name === '') { + hideError(nameError); + } else if (!validateName(name)) { + showError(nameError, 'Name must be 2-50 characters long and contain only letters and spaces'); + } else { + hideError(nameError); + } + + updateSubmitButton(); + }); + + // Real-time mobile validation + mobileInput.addEventListener('input', function() { + let mobile = this.value.replace(/\s/g, ''); + + // Auto-format mobile number (optional) + if (mobile.length > 3 && mobile.length <= 6) { + mobile = mobile.slice(0, 3) + ' ' + mobile.slice(3); + } else if (mobile.length > 6 && mobile.length <= 10) { + mobile = mobile.slice(0, 3) + ' ' + mobile.slice(3, 6) + ' ' + mobile.slice(6); + } + + const rawMobile = mobile.replace(/\s/g, ''); + + if (rawMobile === '') { + hideError(mobileError); + } else if (!validateMobile(rawMobile)) { + showError(mobileError, 'Please enter a valid mobile number (10-15 digits)'); + } else { + hideError(mobileError); + } + + updateSubmitButton(); + }); + + // Format mobile number on blur + mobileInput.addEventListener('blur', function() { + let mobile = this.value.replace(/\s/g, ''); + + // Format mobile number for better readability + if (mobile.length >= 10) { + if (mobile.startsWith('+')) { + // International format + this.value = mobile.slice(0, 1) + ' ' + mobile.slice(1, 4) + ' ' + mobile.slice(4, 7) + ' ' + mobile.slice(7); + } else { + // Domestic format + this.value = mobile.slice(0, 3) + ' ' + mobile.slice(3, 6) + ' ' + mobile.slice(6); + } + } + }); + + // Form submission + form.addEventListener('submit', function(e) { + e.preventDefault(); + + const name = nameInput.value.trim(); + const mobile = mobileInput.value.replace(/\s/g, ''); + + // Final validation + let hasErrors = false; + + if (!validateName(name)) { + showError(nameError, 'Please enter a valid name'); + hasErrors = true; + } + + if (!validateMobile(mobile)) { + showError(mobileError, 'Please enter a valid mobile number'); + hasErrors = true; + } + + if (hasErrors) { + return; + } + + // Show loading state + submitBtn.textContent = 'Submitting...'; + submitBtn.classList.add('loading'); + submitBtn.disabled = true; + + // Simulate form submission (replace with actual API call) + setTimeout(() => { + // Success + successMessage.innerHTML = ` + Success!
+ Name: ${name}
+ Mobile: ${mobile}
+ Form submitted successfully! + `; + successMessage.style.display = 'block'; + + // Reset form after successful submission + form.reset(); + hideError(nameError); + hideError(mobileError); + + // Reset button state + submitBtn.textContent = 'Submit'; + submitBtn.classList.remove('loading'); + submitBtn.disabled = true; + + // Hide success message after 5 seconds + setTimeout(() => { + successMessage.style.display = 'none'; + }, 5000); + + }, 1500); + }); + + // Reset button functionality + form.addEventListener('reset', function() { + hideError(nameError); + hideError(mobileError); + successMessage.style.display = 'none'; + submitBtn.disabled = true; + submitBtn.textContent = 'Submit'; + submitBtn.classList.remove('loading'); + }); + + // Initial state + updateSubmitButton(); +}); + +// Additional utility functions +function formatPhoneNumber(phoneNumber) { + const cleaned = phoneNumber.replace(/\D/g, ''); + + if (cleaned.length === 10) { + return `${cleaned.slice(0, 3)} ${cleaned.slice(3, 6)} ${cleaned.slice(6)}`; + } else if (cleaned.length === 11 && cleaned.startsWith('1')) { + return `+1 ${cleaned.slice(1, 4)} ${cleaned.slice(4, 7)} ${cleaned.slice(7)}`; + } + + return phoneNumber; +} + +// Prevent form submission on Enter key in input fields (optional) +document.querySelectorAll('input').forEach(input => { + input.addEventListener('keydown', function(e) { + if (e.key === 'Enter') { + e.preventDefault(); + const form = this.closest('form'); + if (form) { + form.dispatchEvent(new Event('submit')); + } + } + }); +}); diff --git a/form-style.css b/form-style.css new file mode 100644 index 0000000..f4083b4 --- /dev/null +++ b/form-style.css @@ -0,0 +1,199 @@ +/* Contact Form Styles */ +* { + margin: 0; + padding: 0; + box-sizing: border-box; +} + +body { + font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif; + background: linear-gradient(135deg, #667eea 0%, #764ba2 100%); + min-height: 100vh; + display: flex; + align-items: center; + justify-content: center; + padding: 20px; +} + +.container { + background: rgba(255, 255, 255, 0.95); + padding: 40px; + border-radius: 15px; + box-shadow: 0 20px 40px rgba(0, 0, 0, 0.1); + width: 100%; + max-width: 500px; + backdrop-filter: blur(10px); +} + +h1 { + text-align: center; + color: #333; + margin-bottom: 30px; + font-size: 2rem; + font-weight: 300; +} + +.contact-form { + width: 100%; +} + +.form-group { + margin-bottom: 25px; +} + +label { + display: block; + margin-bottom: 8px; + color: #555; + font-weight: 500; + font-size: 1rem; +} + +input[type="text"], +input[type="tel"] { + width: 100%; + padding: 15px; + border: 2px solid #e1e1e1; + border-radius: 8px; + font-size: 1rem; + transition: all 0.3s ease; + background: #fff; +} + +input[type="text"]:focus, +input[type="tel"]:focus { + outline: none; + border-color: #667eea; + box-shadow: 0 0 0 3px rgba(102, 126, 234, 0.1); + transform: translateY(-2px); +} + +input[type="text"]:valid, +input[type="tel"]:valid { + border-color: #10b981; +} + +input[type="text"]:invalid:not(:placeholder-shown), +input[type="tel"]:invalid:not(:placeholder-shown) { + border-color: #ef4444; +} + +.error-message { + display: block; + color: #ef4444; + font-size: 0.875rem; + margin-top: 5px; + min-height: 20px; +} + +.submit-btn, +.reset-btn { + width: 48%; + padding: 15px; + border: none; + border-radius: 8px; + font-size: 1rem; + font-weight: 600; + cursor: pointer; + transition: all 0.3s ease; + margin-right: 4%; +} + +.submit-btn { + background: linear-gradient(135deg, #667eea 0%, #764ba2 100%); + color: white; +} + +.submit-btn:hover { + transform: translateY(-2px); + box-shadow: 0 10px 25px rgba(102, 126, 234, 0.4); +} + +.submit-btn:disabled { + opacity: 0.6; + cursor: not-allowed; + transform: none; +} + +.reset-btn { + background: #6b7280; + color: white; + margin-right: 0; +} + +.reset-btn:hover { + background: #4b5563; + transform: translateY(-2px); + box-shadow: 0 10px 25px rgba(107, 114, 128, 0.4); +} + +.success-message { + margin-top: 20px; + padding: 15px; + background: #d1fae5; + color: #065f46; + border-radius: 8px; + border-left: 4px solid #10b981; + display: none; +} + +/* Responsive Design */ +@media (max-width: 600px) { + .container { + padding: 30px 20px; + margin: 10px; + } + + h1 { + font-size: 1.5rem; + } + + .submit-btn, + .reset-btn { + width: 100%; + margin-right: 0; + margin-bottom: 10px; + } +} + +/* Animation for form appearance */ +@keyframes slideIn { + from { + opacity: 0; + transform: translateY(30px); + } + to { + opacity: 1; + transform: translateY(0); + } +} + +.container { + animation: slideIn 0.6s ease-out; +} + +/* Loading state */ +.loading { + position: relative; + overflow: hidden; +} + +.loading::after { + content: ''; + position: absolute; + top: 0; + left: -100%; + width: 100%; + height: 100%; + background: linear-gradient(90deg, transparent, rgba(255, 255, 255, 0.4), transparent); + animation: loading 1.5s infinite; +} + +@keyframes loading { + 0% { + left: -100%; + } + 100% { + left: 100%; + } +} diff --git a/greeting-hello-button.html b/greeting-hello-button.html new file mode 100644 index 0000000..8b177a4 --- /dev/null +++ b/greeting-hello-button.html @@ -0,0 +1,281 @@ + + + + + + Greeting Hello Button + + + +
+

Welcome!

+

Click the button below to receive a friendly greeting

+ + + +
+
+
+ + + + diff --git a/hello.html b/hello.html new file mode 100644 index 0000000..c584ae7 --- /dev/null +++ b/hello.html @@ -0,0 +1,100 @@ + + + + + + Hello Page + + + +
+

Hello

+ +
+ + + diff --git a/index.html b/index.html new file mode 100644 index 0000000..c2e8bc7 --- /dev/null +++ b/index.html @@ -0,0 +1,37 @@ + + + + + + Radio Button Selection + + + +
+

Please Make Your Selection

+ +
+
+

Do you agree with the terms and conditions?

+ +
+
+ + +
+ +
+ + +
+
+
+ + +
+
+
+ + + + diff --git a/names_table.html b/names_table.html new file mode 100644 index 0000000..c1d05c8 --- /dev/null +++ b/names_table.html @@ -0,0 +1,42 @@ + + + + + + Random Names Table + + +

Random Names Table

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
IDName
1Alice Johnson
2Michael Chen
3Sarah Williams
4David Rodriguez
5Emma Thompson
+ + diff --git a/projects-script.js b/projects-script.js new file mode 100644 index 0000000..4832118 --- /dev/null +++ b/projects-script.js @@ -0,0 +1,242 @@ +document.addEventListener('DOMContentLoaded', function() { + const cardsWrapper = document.getElementById('cardsWrapper'); + const scrollLeftBtn = document.getElementById('scrollLeft'); + const scrollRightBtn = document.getElementById('scrollRight'); + const indicatorDots = document.getElementById('indicatorDots'); + const projectCards = document.querySelectorAll('.project-card'); + + // Scroll amount (one card width + gap) + const scrollAmount = 380; + + // Initialize scroll indicator dots + function initIndicatorDots() { + const numCards = projectCards.length; + const cardsPerView = Math.floor(cardsWrapper.clientWidth / 380); + const numDots = Math.ceil(numCards / cardsPerView); + + indicatorDots.innerHTML = ''; + for (let i = 0; i < numDots; i++) { + const dot = document.createElement('div'); + dot.className = 'indicator-dot'; + if (i === 0) dot.classList.add('active'); + dot.addEventListener('click', () => scrollToSection(i)); + indicatorDots.appendChild(dot); + } + } + + // Scroll to specific section + function scrollToSection(index) { + const cardsPerView = Math.floor(cardsWrapper.clientWidth / 380); + const scrollPosition = index * cardsPerView * scrollAmount; + cardsWrapper.scrollTo({ + left: scrollPosition, + behavior: 'smooth' + }); + } + + // Update active indicator dot + function updateIndicator() { + const dots = indicatorDots.querySelectorAll('.indicator-dot'); + const cardsPerView = Math.floor(cardsWrapper.clientWidth / 380); + const scrollPosition = cardsWrapper.scrollLeft; + const activeIndex = Math.round(scrollPosition / (cardsPerView * scrollAmount)); + + dots.forEach((dot, index) => { + dot.classList.toggle('active', index === activeIndex); + }); + + updateScrollButtons(); + } + + // Update scroll button states + function updateScrollButtons() { + const maxScroll = cardsWrapper.scrollWidth - cardsWrapper.clientWidth; + scrollLeftBtn.disabled = cardsWrapper.scrollLeft <= 0; + scrollRightBtn.disabled = cardsWrapper.scrollLeft >= maxScroll - 5; + } + + // Scroll left button + scrollLeftBtn.addEventListener('click', () => { + cardsWrapper.scrollBy({ + left: -scrollAmount, + behavior: 'smooth' + }); + }); + + // Scroll right button + scrollRightBtn.addEventListener('click', () => { + cardsWrapper.scrollBy({ + left: scrollAmount, + behavior: 'smooth' + }); + }); + + // Listen to scroll events + cardsWrapper.addEventListener('scroll', () => { + updateIndicator(); + }); + + // Handle window resize + let resizeTimer; + window.addEventListener('resize', () => { + clearTimeout(resizeTimer); + resizeTimer = setTimeout(() => { + initIndicatorDots(); + updateIndicator(); + }, 250); + }); + + // Touch/swipe support for mobile + let touchStartX = 0; + let touchEndX = 0; + let isDragging = false; + let startScrollLeft = 0; + + cardsWrapper.addEventListener('touchstart', (e) => { + touchStartX = e.touches[0].clientX; + startScrollLeft = cardsWrapper.scrollLeft; + isDragging = true; + }, { passive: true }); + + cardsWrapper.addEventListener('touchmove', (e) => { + if (!isDragging) return; + touchEndX = e.touches[0].clientX; + const diff = touchStartX - touchEndX; + cardsWrapper.scrollLeft = startScrollLeft + diff; + }, { passive: true }); + + cardsWrapper.addEventListener('touchend', () => { + isDragging = false; + }); + + // Mouse drag support for desktop + let mouseDown = false; + let startX; + let scrollLeft; + + cardsWrapper.addEventListener('mousedown', (e) => { + mouseDown = true; + startX = e.pageX - cardsWrapper.offsetLeft; + scrollLeft = cardsWrapper.scrollLeft; + cardsWrapper.style.cursor = 'grabbing'; + }); + + cardsWrapper.addEventListener('mouseleave', () => { + mouseDown = false; + cardsWrapper.style.cursor = 'grab'; + }); + + cardsWrapper.addEventListener('mouseup', () => { + mouseDown = false; + cardsWrapper.style.cursor = 'grab'; + }); + + cardsWrapper.addEventListener('mousemove', (e) => { + if (!mouseDown) return; + e.preventDefault(); + const x = e.pageX - cardsWrapper.offsetLeft; + const walk = (x - startX) * 2; + cardsWrapper.scrollLeft = scrollLeft - walk; + }); + + // Set cursor style + cardsWrapper.style.cursor = 'grab'; + + // Keyboard navigation + document.addEventListener('keydown', (e) => { + if (e.key === 'ArrowLeft') { + cardsWrapper.scrollBy({ + left: -scrollAmount, + behavior: 'smooth' + }); + } else if (e.key === 'ArrowRight') { + cardsWrapper.scrollBy({ + left: scrollAmount, + behavior: 'smooth' + }); + } + }); + + // Handle view button clicks + const viewButtons = document.querySelectorAll('.view-btn'); + viewButtons.forEach((btn, index) => { + btn.addEventListener('click', (e) => { + e.stopPropagation(); + const card = btn.closest('.project-card'); + const title = card.querySelector('.card-title').textContent; + + // Add animation + btn.style.transform = 'scale(0.95)'; + setTimeout(() => { + btn.style.transform = 'scale(1)'; + }, 150); + + // Show alert (replace with actual navigation) + setTimeout(() => { + alert(`Opening project: ${title}\n\nThis would navigate to the project details page.`); + }, 200); + }); + }); + + // Handle card clicks + projectCards.forEach((card) => { + card.addEventListener('click', (e) => { + if (!e.target.classList.contains('view-btn')) { + const title = card.querySelector('.card-title').textContent; + console.log(`Card clicked: ${title}`); + } + }); + }); + + // Auto-scroll feature (optional - uncomment to enable) + /* + let autoScrollInterval; + let isAutoScrolling = false; + + function startAutoScroll() { + if (isAutoScrolling) return; + isAutoScrolling = true; + + autoScrollInterval = setInterval(() => { + const maxScroll = cardsWrapper.scrollWidth - cardsWrapper.clientWidth; + + if (cardsWrapper.scrollLeft >= maxScroll - 5) { + cardsWrapper.scrollTo({ left: 0, behavior: 'smooth' }); + } else { + cardsWrapper.scrollBy({ left: scrollAmount, behavior: 'smooth' }); + } + }, 3000); + } + + function stopAutoScroll() { + isAutoScrolling = false; + clearInterval(autoScrollInterval); + } + + // Start auto-scroll after 2 seconds + setTimeout(startAutoScroll, 2000); + + // Stop auto-scroll on user interaction + cardsWrapper.addEventListener('mouseenter', stopAutoScroll); + cardsWrapper.addEventListener('touchstart', stopAutoScroll); + scrollLeftBtn.addEventListener('click', stopAutoScroll); + scrollRightBtn.addEventListener('click', stopAutoScroll); + */ + + // Initialize + initIndicatorDots(); + updateIndicator(); + + // Add smooth entrance animation + setTimeout(() => { + projectCards.forEach((card, index) => { + setTimeout(() => { + card.style.opacity = '1'; + }, index * 100); + }); + }, 100); + + // Log initialization + console.log('Project card scroller initialized'); + console.log(`Total cards: ${projectCards.length}`); +}); diff --git a/projects-style.css b/projects-style.css new file mode 100644 index 0000000..cd3e99f --- /dev/null +++ b/projects-style.css @@ -0,0 +1,359 @@ +/* Reset and base styles */ +* { + margin: 0; + padding: 0; + box-sizing: border-box; +} + +body { + font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif; + background: linear-gradient(135deg, #667eea 0%, #764ba2 100%); + min-height: 100vh; + padding: 20px; +} + +.page-container { + max-width: 1400px; + margin: 0 auto; +} + +/* Header styles */ +.header { + text-align: center; + color: white; + margin-bottom: 50px; + padding: 20px; +} + +.header h1 { + font-size: 3rem; + margin-bottom: 10px; + font-weight: 700; + text-shadow: 2px 2px 4px rgba(0, 0, 0, 0.2); +} + +.subtitle { + font-size: 1.2rem; + opacity: 0.95; + font-weight: 300; +} + +/* Scroller container */ +.scroller-container { + position: relative; + padding: 0 60px; + margin-bottom: 30px; +} + +/* Cards wrapper - horizontal scroll */ +.cards-wrapper { + display: flex; + gap: 30px; + overflow-x: auto; + scroll-behavior: smooth; + padding: 20px 10px; + scrollbar-width: none; /* Firefox */ + -ms-overflow-style: none; /* IE and Edge */ +} + +.cards-wrapper::-webkit-scrollbar { + display: none; /* Chrome, Safari, Opera */ +} + +/* Project card */ +.project-card { + flex: 0 0 350px; + background: white; + border-radius: 15px; + overflow: hidden; + box-shadow: 0 10px 30px rgba(0, 0, 0, 0.2); + transition: transform 0.3s ease, box-shadow 0.3s ease; + cursor: pointer; +} + +.project-card:hover { + transform: translateY(-10px); + box-shadow: 0 15px 40px rgba(0, 0, 0, 0.3); +} + +/* Card image */ +.card-image { + position: relative; + width: 100%; + height: 220px; + overflow: hidden; +} + +.card-image img { + width: 100%; + height: 100%; + object-fit: cover; + transition: transform 0.5s ease; +} + +.project-card:hover .card-image img { + transform: scale(1.1); +} + +/* Card overlay */ +.card-overlay { + position: absolute; + top: 0; + left: 0; + right: 0; + bottom: 0; + background: rgba(102, 126, 234, 0.9); + display: flex; + align-items: center; + justify-content: center; + opacity: 0; + transition: opacity 0.3s ease; +} + +.project-card:hover .card-overlay { + opacity: 1; +} + +.view-btn { + padding: 12px 30px; + background: white; + color: #667eea; + border: none; + border-radius: 25px; + font-size: 1rem; + font-weight: 600; + cursor: pointer; + transition: transform 0.2s ease, box-shadow 0.2s ease; +} + +.view-btn:hover { + transform: scale(1.05); + box-shadow: 0 5px 15px rgba(0, 0, 0, 0.3); +} + +/* Card content */ +.card-content { + padding: 25px; +} + +.card-title { + font-size: 1.5rem; + color: #333; + margin-bottom: 12px; + font-weight: 600; +} + +.card-description { + font-size: 0.95rem; + color: #666; + line-height: 1.6; + margin-bottom: 15px; +} + +/* Tags */ +.card-tags { + display: flex; + flex-wrap: wrap; + gap: 8px; +} + +.tag { + padding: 6px 14px; + background: linear-gradient(135deg, #667eea 0%, #764ba2 100%); + color: white; + border-radius: 20px; + font-size: 0.85rem; + font-weight: 500; +} + +/* Scroll buttons */ +.scroll-btn { + position: absolute; + top: 50%; + transform: translateY(-50%); + width: 50px; + height: 50px; + background: white; + border: none; + border-radius: 50%; + display: flex; + align-items: center; + justify-content: center; + cursor: pointer; + box-shadow: 0 5px 15px rgba(0, 0, 0, 0.2); + transition: all 0.3s ease; + z-index: 10; + color: #667eea; +} + +.scroll-btn:hover { + background: #667eea; + color: white; + transform: translateY(-50%) scale(1.1); +} + +.scroll-btn:active { + transform: translateY(-50%) scale(0.95); +} + +.scroll-btn-left { + left: 0; +} + +.scroll-btn-right { + right: 0; +} + +.scroll-btn:disabled { + opacity: 0.3; + cursor: not-allowed; +} + +.scroll-btn:disabled:hover { + background: white; + color: #667eea; + transform: translateY(-50%) scale(1); +} + +/* Scroll indicator */ +.scroll-indicator { + display: flex; + justify-content: center; + padding: 20px; +} + +.indicator-dots { + display: flex; + gap: 10px; +} + +.indicator-dot { + width: 10px; + height: 10px; + border-radius: 50%; + background: rgba(255, 255, 255, 0.4); + cursor: pointer; + transition: all 0.3s ease; +} + +.indicator-dot.active { + background: white; + width: 30px; + border-radius: 5px; +} + +.indicator-dot:hover { + background: rgba(255, 255, 255, 0.7); +} + +/* Responsive design */ +@media (max-width: 768px) { + body { + padding: 10px; + } + + .header h1 { + font-size: 2rem; + } + + .subtitle { + font-size: 1rem; + } + + .scroller-container { + padding: 0 10px; + } + + .scroll-btn { + display: none; + } + + .project-card { + flex: 0 0 280px; + } + + .card-image { + height: 180px; + } + + .card-content { + padding: 20px; + } + + .card-title { + font-size: 1.3rem; + } + + .card-description { + font-size: 0.9rem; + } + + /* Show overlay on mobile by default for better UX */ + .card-overlay { + opacity: 0; + } +} + +@media (max-width: 480px) { + .header { + margin-bottom: 30px; + } + + .header h1 { + font-size: 1.8rem; + } + + .subtitle { + font-size: 0.9rem; + } + + .project-card { + flex: 0 0 260px; + } + + .card-image { + height: 160px; + } + + .card-content { + padding: 15px; + } + + .card-title { + font-size: 1.2rem; + } + + .card-description { + font-size: 0.85rem; + } + + .tag { + font-size: 0.75rem; + padding: 5px 12px; + } +} + +/* Smooth animations */ +@keyframes fadeIn { + from { + opacity: 0; + transform: translateY(20px); + } + to { + opacity: 1; + transform: translateY(0); + } +} + +.project-card { + animation: fadeIn 0.5s ease forwards; +} + +.project-card:nth-child(1) { animation-delay: 0.1s; } +.project-card:nth-child(2) { animation-delay: 0.2s; } +.project-card:nth-child(3) { animation-delay: 0.3s; } +.project-card:nth-child(4) { animation-delay: 0.4s; } +.project-card:nth-child(5) { animation-delay: 0.5s; } +.project-card:nth-child(6) { animation-delay: 0.6s; } +.project-card:nth-child(7) { animation-delay: 0.7s; } +.project-card:nth-child(8) { animation-delay: 0.8s; } diff --git a/projects.html b/projects.html new file mode 100644 index 0000000..39a933d --- /dev/null +++ b/projects.html @@ -0,0 +1,183 @@ + + + + + + Our Projects - Portfolio Showcase + + + +
+
+

Our Projects

+

Explore our latest work and creative solutions

+
+ +
+ + +
+
+
+ E-Commerce Platform +
+ +
+
+
+

E-Commerce Platform

+

A modern online shopping experience with seamless checkout and inventory management.

+
+ React + Node.js + MongoDB +
+
+
+ +
+
+ Analytics Dashboard +
+ +
+
+
+

Analytics Dashboard

+

Real-time data visualization and insights for business intelligence and decision making.

+
+ Vue.js + D3.js + Python +
+
+
+ +
+
+ Mobile Banking App +
+ +
+
+
+

Mobile Banking App

+

Secure and intuitive mobile banking solution with biometric authentication.

+
+ React Native + Firebase + TypeScript +
+
+
+ +
+
+ Task Management System +
+ +
+
+
+

Task Management System

+

Collaborative project management tool with real-time updates and team coordination.

+
+ Angular + Express + PostgreSQL +
+
+
+ +
+
+ Social Media Platform +
+ +
+
+
+

Social Media Platform

+

Connect and share with friends through posts, stories, and real-time messaging.

+
+ Next.js + GraphQL + Redis +
+
+
+ +
+
+ Fitness Tracking App +
+ +
+
+
+

Fitness Tracking App

+

Track workouts, nutrition, and health metrics with personalized fitness plans.

+
+ Flutter + Django + ML +
+
+
+ +
+
+ CRM Solution +
+ +
+
+
+

CRM Solution

+

Customer relationship management system with sales pipeline and automation tools.

+
+ Svelte + FastAPI + MySQL +
+
+
+ +
+
+ Learning Management System +
+ +
+
+
+

Learning Management System

+

Online education platform with courses, quizzes, and progress tracking features.

+
+ React + Laravel + AWS +
+
+
+
+ + +
+ +
+
+
+
+ + + + diff --git a/random_contacts_table.html b/random_contacts_table.html new file mode 100644 index 0000000..6551543 --- /dev/null +++ b/random_contacts_table.html @@ -0,0 +1,266 @@ + + + + + + Random Contacts Directory + + + +
+
+

📞 Random Contacts Directory

+

A collection of randomly generated contact information

+
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
#Full NamePhone Number
1Sarah Johnson(555) 123-4567
2Michael Chen(555) 987-6543
3Emily Rodriguez(555) 246-8135
4David Thompson(555) 369-2580
5Jessica Williams(555) 741-9630
6James Anderson(555) 852-7419
7Ashley Martinez(555) 963-1470
8Robert Davis(555) 159-3570
9Amanda Wilson(555) 753-9514
10Christopher Brown(555) 486-2759
11Jennifer Garcia(555) 317-6842
12Matthew Miller(555) 928-4613
13Samantha Lee(555) 604-7251
14Daniel Taylor(555) 815-3962
15Lauren Moore(555) 492-6078
16Andrew Jackson(555) 537-1849
17Megan White(555) 263-8450
18Kevin Harris(555) 680-2174
19Nicole Thomas(555) 394-7562
20Brandon Clark(555) 751-4829
+
+
+ + diff --git a/reactive-forms/src/app/app.component.html b/reactive-forms/src/app/app.component.html index bb3d76b..34f2e06 100644 --- a/reactive-forms/src/app/app.component.html +++ b/reactive-forms/src/app/app.component.html @@ -1,4 +1,5 @@
+

Registration Form

@@ -68,3 +69,7 @@

Registration Form

{{registrationForm.status | json}} {{registrationForm.value | json}}
+ + +
+ diff --git a/reactive-forms/src/app/app.module.ts b/reactive-forms/src/app/app.module.ts index b34cdfa..bd1c38c 100644 --- a/reactive-forms/src/app/app.module.ts +++ b/reactive-forms/src/app/app.module.ts @@ -3,10 +3,12 @@ import { NgModule } from '@angular/core'; import { ReactiveFormsModule } from '@angular/forms'; import { HttpClientModule } from '@angular/common/http'; import { AppComponent } from './app.component'; +import { UserFormComponent } from './user-form.component'; @NgModule({ declarations: [ - AppComponent + AppComponent, + UserFormComponent ], imports: [ BrowserModule, diff --git a/reactive-forms/src/app/user-form.component.css b/reactive-forms/src/app/user-form.component.css new file mode 100644 index 0000000..9167015 --- /dev/null +++ b/reactive-forms/src/app/user-form.component.css @@ -0,0 +1,253 @@ +/* Form Container */ +.form-container { + display: flex; + justify-content: center; + align-items: center; + min-height: 100vh; + background: linear-gradient(135deg, #667eea 0%, #764ba2 100%); + padding: 20px; + font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif; +} + +.form-card { + background: white; + padding: 40px; + border-radius: 15px; + box-shadow: 0 15px 35px rgba(0, 0, 0, 0.1); + width: 100%; + max-width: 500px; + transition: transform 0.2s ease; +} + +.form-card:hover { + transform: translateY(-2px); +} + +/* Form Title */ +.form-title { + color: #333; + font-size: 28px; + font-weight: 700; + margin-bottom: 10px; + text-align: center; +} + +.form-subtitle { + color: #666; + font-size: 16px; + text-align: center; + margin-bottom: 30px; +} + +/* Form Groups */ +.form-group { + margin-bottom: 25px; +} + +.form-label { + display: block; + color: #333; + font-size: 16px; + font-weight: 600; + margin-bottom: 8px; +} + +.required { + color: #e74c3c; + font-weight: bold; +} + +/* Form Inputs */ +.form-input { + width: 100%; + padding: 12px 16px; + font-size: 16px; + border: 2px solid #e1e5e9; + border-radius: 8px; + transition: all 0.3s ease; + background-color: #fafbfc; + box-sizing: border-box; +} + +.form-input:focus { + outline: none; + border-color: #667eea; + background-color: white; + box-shadow: 0 0 0 3px rgba(102, 126, 234, 0.1); +} + +.form-input:hover:not(:focus) { + border-color: #c5c9d0; +} + +.form-input.error { + border-color: #e74c3c; + background-color: #fdf2f2; +} + +.form-input.error:focus { + box-shadow: 0 0 0 3px rgba(231, 76, 60, 0.1); +} + +/* Error Messages */ +.error-message { + color: #e74c3c; + font-size: 14px; + margin-top: 5px; + display: flex; + align-items: center; + animation: slideDown 0.3s ease; +} + +.error-message:before { + content: "⚠️"; + margin-right: 5px; +} + +@keyframes slideDown { + from { + opacity: 0; + transform: translateY(-10px); + } + to { + opacity: 1; + transform: translateY(0); + } +} + +/* Form Actions */ +.form-actions { + display: flex; + gap: 15px; + margin-top: 30px; + justify-content: space-between; +} + +.btn { + padding: 12px 24px; + font-size: 16px; + font-weight: 600; + border: none; + border-radius: 8px; + cursor: pointer; + transition: all 0.3s ease; + flex: 1; + text-transform: uppercase; + letter-spacing: 0.5px; +} + +.btn-primary { + background: linear-gradient(45deg, #667eea, #764ba2); + color: white; +} + +.btn-primary:hover:not(:disabled) { + background: linear-gradient(45deg, #5a6fd8, #6a4190); + transform: translateY(-2px); + box-shadow: 0 5px 15px rgba(102, 126, 234, 0.3); +} + +.btn-secondary { + background: #f8f9fa; + color: #6c757d; + border: 2px solid #e9ecef; +} + +.btn-secondary:hover:not(:disabled) { + background: #e9ecef; + color: #495057; + transform: translateY(-1px); +} + +.btn:disabled { + opacity: 0.5; + cursor: not-allowed; + transform: none; +} + +.btn:active:not(:disabled) { + transform: translateY(0); +} + +/* Form Status */ +.form-status { + margin-top: 20px; + padding: 15px; + background: #f8f9fa; + border-radius: 8px; + border-left: 4px solid #6c757d; +} + +.status-item { + margin-bottom: 10px; +} + +.status-item:last-child { + margin-bottom: 0; +} + +.valid { + color: #28a745; + font-weight: bold; +} + +.invalid { + color: #e74c3c; + font-weight: bold; +} + +.error-list { + margin: 5px 0 0 20px; + color: #e74c3c; +} + +.error-list li { + margin-bottom: 3px; +} + +/* Responsive Design */ +@media (max-width: 600px) { + .form-container { + padding: 15px; + } + + .form-card { + padding: 30px 20px; + } + + .form-title { + font-size: 24px; + } + + .form-actions { + flex-direction: column; + } + + .btn { + width: 100%; + } +} + +/* Loading State */ +.loading { + opacity: 0.7; + pointer-events: none; +} + +/* Success Animation */ +@keyframes success { + 0% { + transform: scale(1); + } + 50% { + transform: scale(1.05); + } + 100% { + transform: scale(1); + } +} + +.form-card.success { + animation: success 0.6s ease; + border: 2px solid #28a745; +} diff --git a/reactive-forms/src/app/user-form.component.html b/reactive-forms/src/app/user-form.component.html new file mode 100644 index 0000000..9d12101 --- /dev/null +++ b/reactive-forms/src/app/user-form.component.html @@ -0,0 +1,86 @@ +
+
+

User Information Form

+

Please fill in your details below

+ + + + +
+ + +
+ {{ getErrorMessage('name') }} +
+
+ + +
+ + +
+ {{ getErrorMessage('email') }} +
+
+ + +
+ + +
+ + +
+
+ Form Status: + + {{ userForm.valid ? 'Valid' : 'Invalid' }} + +
+
+ Errors: +
    +
  • Name is required
  • +
  • Name is too short
  • +
  • Name contains invalid characters
  • +
  • Email is required
  • +
  • Email format is invalid
  • +
+
+
+ +
+
diff --git a/reactive-forms/src/app/user-form.component.ts b/reactive-forms/src/app/user-form.component.ts new file mode 100644 index 0000000..000be85 --- /dev/null +++ b/reactive-forms/src/app/user-form.component.ts @@ -0,0 +1,111 @@ +import { Component, OnInit } from '@angular/core'; +import { FormBuilder, FormGroup, Validators } from '@angular/forms'; + +@Component({ + selector: 'app-user-form', + templateUrl: './user-form.component.html', + styleUrls: ['./user-form.component.css'] +}) +export class UserFormComponent implements OnInit { + userForm: FormGroup; + isSubmitted = false; + + constructor(private formBuilder: FormBuilder) { } + + ngOnInit(): void { + this.initializeForm(); + } + + initializeForm(): void { + this.userForm = this.formBuilder.group({ + name: ['', [ + Validators.required, + Validators.minLength(2), + Validators.maxLength(50), + Validators.pattern(/^[a-zA-Z\s]*$/) + ]], + email: ['', [ + Validators.required, + Validators.email, + Validators.maxLength(100) + ]] + }); + } + + // Getter methods for easy access to form fields + get name() { + return this.userForm.get('name'); + } + + get email() { + return this.userForm.get('email'); + } + + onSubmit(): void { + this.isSubmitted = true; + + if (this.userForm.valid) { + const formData = this.userForm.value; + console.log('Form Data:', formData); + + // Here you would typically send the data to a service + alert(`Form submitted successfully!\nName: ${formData.name}\nEmail: ${formData.email}`); + + // Reset form after successful submission + this.resetForm(); + } else { + console.log('Form is invalid'); + this.markFormGroupTouched(); + } + } + + resetForm(): void { + this.userForm.reset(); + this.isSubmitted = false; + } + + private markFormGroupTouched(): void { + Object.keys(this.userForm.controls).forEach(key => { + const control = this.userForm.get(key); + control?.markAsTouched(); + }); + } + + // Helper method to check if field has error + hasError(fieldName: string, errorType: string): boolean { + const field = this.userForm.get(fieldName); + return field ? field.hasError(errorType) && (field.dirty || field.touched || this.isSubmitted) : false; + } + + // Helper method to get error message + getErrorMessage(fieldName: string): string { + const field = this.userForm.get(fieldName); + if (!field || !field.errors || (!field.touched && !this.isSubmitted)) { + return ''; + } + + const errors = field.errors; + + if (errors['required']) { + return `${this.capitalizeFirst(fieldName)} is required`; + } + if (errors['email']) { + return 'Please enter a valid email address'; + } + if (errors['minlength']) { + return `${this.capitalizeFirst(fieldName)} must be at least ${errors['minlength'].requiredLength} characters`; + } + if (errors['maxlength']) { + return `${this.capitalizeFirst(fieldName)} cannot exceed ${errors['maxlength'].requiredLength} characters`; + } + if (errors['pattern']) { + return `${this.capitalizeFirst(fieldName)} can only contain letters and spaces`; + } + + return 'Invalid input'; + } + + private capitalizeFirst(str: string): string { + return str.charAt(0).toUpperCase() + str.slice(1); + } +} diff --git a/script.js b/script.js new file mode 100644 index 0000000..0ecea4c --- /dev/null +++ b/script.js @@ -0,0 +1,64 @@ +document.addEventListener('DOMContentLoaded', function() { + const form = document.getElementById('radioForm'); + const result = document.getElementById('result'); + + // Handle form submission + form.addEventListener('submit', function(e) { + e.preventDefault(); + + // Get the selected radio button value + const selectedOption = document.querySelector('input[name="answer"]:checked'); + + if (selectedOption) { + const answer = selectedOption.value; + showResult(answer); + } else { + showError('Please select an option before submitting.'); + } + }); + + // Add click animation to radio options + const radioOptions = document.querySelectorAll('.radio-option'); + radioOptions.forEach(option => { + option.addEventListener('click', function() { + const radio = this.querySelector('input[type="radio"]'); + radio.checked = true; + + // Add visual feedback + this.style.transform = 'scale(0.98)'; + setTimeout(() => { + this.style.transform = 'scale(1)'; + }, 150); + }); + }); + + function showResult(answer) { + result.className = 'result success'; + result.innerHTML = ` + Thank you for your response!
+ You selected: ${answer.charAt(0).toUpperCase() + answer.slice(1)} + `; + result.style.display = 'block'; + + // Scroll to result + result.scrollIntoView({ behavior: 'smooth', block: 'nearest' }); + } + + function showError(message) { + result.className = 'result error'; + result.textContent = message; + result.style.display = 'block'; + + // Hide error after 3 seconds + setTimeout(() => { + result.style.display = 'none'; + }, 3000); + } + + // Add keyboard navigation support + document.addEventListener('keydown', function(e) { + if (e.key === 'Enter' && document.activeElement.type === 'radio') { + form.dispatchEvent(new Event('submit')); + } + }); +}); diff --git a/style.css b/style.css new file mode 100644 index 0000000..d47cef2 --- /dev/null +++ b/style.css @@ -0,0 +1,167 @@ +/* Reset and base styles */ +* { + margin: 0; + padding: 0; + box-sizing: border-box; +} + +body { + font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif; + background: linear-gradient(135deg, #667eea 0%, #764ba2 100%); + min-height: 100vh; + display: flex; + align-items: center; + justify-content: center; +} + +.container { + background: white; + padding: 40px; + border-radius: 15px; + box-shadow: 0 15px 35px rgba(0, 0, 0, 0.1); + max-width: 500px; + width: 90%; +} + +h1 { + text-align: center; + color: #333; + margin-bottom: 30px; + font-size: 2rem; +} + +.question h2 { + color: #555; + margin-bottom: 20px; + font-size: 1.3rem; + font-weight: 500; +} + +.radio-group { + display: flex; + flex-direction: column; + gap: 15px; + margin-bottom: 30px; +} + +.radio-option { + display: flex; + align-items: center; + padding: 15px 20px; + border: 2px solid #e0e0e0; + border-radius: 8px; + cursor: pointer; + transition: all 0.3s ease; +} + +.radio-option:hover { + border-color: #667eea; + background-color: #f8f9ff; +} + +.radio-option input[type="radio"] { + margin-right: 15px; + width: 20px; + height: 20px; + cursor: pointer; +} + +.radio-option label { + font-size: 1.1rem; + color: #333; + cursor: pointer; + flex: 1; +} + +/* Custom radio button styling */ +input[type="radio"] { + appearance: none; + border: 2px solid #ddd; + border-radius: 50%; + position: relative; +} + +input[type="radio"]:checked { + border-color: #667eea; +} + +input[type="radio"]:checked::after { + content: ''; + position: absolute; + top: 50%; + left: 50%; + transform: translate(-50%, -50%); + width: 10px; + height: 10px; + background-color: #667eea; + border-radius: 50%; +} + +.radio-option:has(input[type="radio"]:checked) { + border-color: #667eea; + background-color: #f8f9ff; +} + +.submit-btn { + width: 100%; + padding: 15px; + background: linear-gradient(135deg, #667eea 0%, #764ba2 100%); + color: white; + border: none; + border-radius: 8px; + font-size: 1.1rem; + font-weight: 600; + cursor: pointer; + transition: transform 0.2s ease; +} + +.submit-btn:hover { + transform: translateY(-2px); +} + +.submit-btn:active { + transform: translateY(0); +} + +.result { + margin-top: 20px; + padding: 15px; + border-radius: 8px; + font-weight: 600; + text-align: center; + display: none; +} + +.result.success { + background-color: #d4edda; + color: #155724; + border: 1px solid #c3e6cb; + display: block; +} + +.result.error { + background-color: #f8d7da; + color: #721c24; + border: 1px solid #f5c6cb; + display: block; +} + +/* Responsive design */ +@media (max-width: 480px) { + .container { + padding: 25px; + margin: 20px; + } + + h1 { + font-size: 1.5rem; + } + + .question h2 { + font-size: 1.1rem; + } + + .radio-option { + padding: 12px 15px; + } +} diff --git a/test-form.html b/test-form.html new file mode 100644 index 0000000..b32c244 --- /dev/null +++ b/test-form.html @@ -0,0 +1,80 @@ + + + + + + Form Test + + +

Testing Form Components

+ +

Test Results:

+ + + + + diff --git a/videos/browser_session_1762783538908.webm b/videos/browser_session_1762783538908.webm new file mode 100644 index 0000000..a4463e2 Binary files /dev/null and b/videos/browser_session_1762783538908.webm differ