feat: set up how can we help section

This commit is contained in:
2026-02-02 13:46:46 -08:00
parent 495a8f089b
commit 35ce4fc4d7
+409
View File
@@ -521,6 +521,43 @@
}
}
/* ============================================
ROTATING TEXT
============================================ */
#rotating-text {
text-align: center;
display: flex !important;
align-items: center !important;
justify-content: center !important;
}
.rotating-option {
white-space: nowrap;
display: block;
}
@media (max-width: 768px) {
#rotating-text {
min-width: 200px !important;
max-width: 250px !important;
}
.rotating-option {
font-size: calc(var(--dynamic-size, 1.2rem) * 0.85) !important;
}
}
@media (max-width: 480px) {
#rotating-text {
min-width: 180px !important;
max-width: 220px !important;
}
.rotating-option {
font-size: calc(var(--dynamic-size, 1rem) * 0.75) !important;
}
}
/* ============================================
RESPONSIVE DESIGN
============================================ */
@@ -725,6 +762,378 @@
</p>
</section>
<!--
MARK: How Can We Serve You?
-->
<section class="card fade-in" style="text-align: center; background: linear-gradient(135deg, #5865F2 0%, #4752C4 100%); color: white; position: relative;" role="region" aria-labelledby="serve-you">
<h2 id="serve-you" style="margin-top: 0; color: white;">How Can We Best Serve You?</h2>
<div style="margin: 2rem auto; padding: 0 1rem;">
<div style="display: flex; align-items: center; justify-content: center; gap: 0.5rem; flex-wrap: wrap;">
<span style="margin-bottom: 0.5rem; font-size: 1.4rem;">I need help with</span>
</div>
<div style="display: flex; align-items: center; justify-content: center; gap: 1rem; margin-top: 1rem;">
<button id="prev-service" aria-label="Previous service" style="background: rgba(255, 255, 255, 0.2); border: none; color: white; width: 40px; height: 40px; border-radius: 50%; cursor: pointer; display: flex; align-items: center; justify-content: center; transition: all 0.3s ease; font-size: 1.2rem; flex-shrink: 0;">
<i class="fas fa-chevron-left"></i>
</button>
<span id="rotating-text" style="font-weight: bold; color: #ffd700; display: flex; align-items: center; justify-content: center; min-width: 220px; max-width: 350px; height: 40px; position: relative; cursor: pointer; text-align: center;">
<span class="rotating-option" style="position: absolute; width: 100%; left: 0; opacity: 0; transform: translateY(20px); transition: all 0.5s ease;">Discord bots</span>
</span>
<button id="next-service" aria-label="Next service" style="background: rgba(255, 255, 255, 0.2); border: none; color: white; width: 40px; height: 40px; border-radius: 50%; cursor: pointer; display: flex; align-items: center; justify-content: center; transition: all 0.3s ease; font-size: 1.2rem; flex-shrink: 0;">
<i class="fas fa-chevron-right"></i>
</button>
</div>
</div>
<!-- Service details that change based on selection -->
<div id="service-details" style="min-height: 150px; margin: 2rem 0; padding: 1.5rem; border-radius: 16px;">
<h3 id="service-title" style="color: #ffd700; margin-top: 0; text-shadow: 0 2px 4px rgba(0, 0, 0, 0.2);">Discord Bot Development</h3>
<p id="service-description" style="font-size: 1.1rem; margin: 1rem 0; text-shadow: 0 1px 2px rgba(0, 0, 0, 0.1);">
Custom Discord bots tailored to your community's needs. From moderation tools to interactive games, we build scalable solutions that enhance engagement.
</p>
<div id="service-features" style="display: flex; justify-content: center; gap: 2rem; flex-wrap: wrap; margin-top: 1.5rem;">
<span style="display: flex; align-items: center; gap: 0.5rem; text-shadow: 0 1px 2px rgba(0, 0, 0, 0.1);"><i class="fas fa-check-circle" style="color: #ffd700; filter: drop-shadow(0 1px 2px rgba(0, 0, 0, 0.2));"></i> Custom Commands</span>
<span style="display: flex; align-items: center; gap: 0.5rem; text-shadow: 0 1px 2px rgba(0, 0, 0, 0.1);"><i class="fas fa-check-circle" style="color: #ffd700; filter: drop-shadow(0 1px 2px rgba(0, 0, 0, 0.2));"></i> Auto-moderation</span>
<span style="display: flex; align-items: center; gap: 0.5rem; text-shadow: 0 1px 2px rgba(0, 0, 0, 0.1);"><i class="fas fa-check-circle" style="color: #ffd700; filter: drop-shadow(0 1px 2px rgba(0, 0, 0, 0.2));"></i> 24/7 Uptime</span>
</div>
</div>
<!-- Service selection dots -->
<div id="service-dots" style="display: flex; justify-content: center; gap: 0.5rem; margin: 1rem 0;">
<!-- Dots will be generated by JavaScript -->
</div>
<div style="margin-top: 2rem;">
<a href="https://forms.nhcarrigan.com/form/XRlQjeu8CbMrTA-v0IPOxlUPEPitLKXTWg70UUCIORA" target="_blank" class="cta-button" style="background: white; color: #5865F2;" aria-label="Submit a commission inquiry">
<i class="fas fa-rocket" aria-hidden="true"></i> Let's Work Together
</a>
</div>
</section>
<style>
#prev-service:hover, #next-service:hover {
background: rgba(255, 255, 255, 0.3) !important;
transform: scale(1.1);
}
#prev-service:active, #next-service:active {
transform: scale(0.95);
}
.service-dot {
width: 10px;
height: 10px;
border-radius: 50%;
background: rgba(255, 255, 255, 0.3);
border: none;
cursor: pointer;
transition: all 0.3s ease;
padding: 0;
}
.service-dot.active {
background: #ffd700;
transform: scale(1.3);
}
.service-dot:hover {
background: rgba(255, 255, 255, 0.5);
}
#service-details {
position: relative;
background: linear-gradient(135deg, rgba(255, 255, 255, 0.1) 0%, rgba(255, 255, 255, 0.05) 100%) !important;
backdrop-filter: blur(20px) saturate(180%) !important;
-webkit-backdrop-filter: blur(20px) saturate(180%) !important;
border: 1px solid rgba(255, 255, 255, 0.25) !important;
box-shadow:
0 8px 32px 0 rgba(31, 38, 135, 0.2),
inset 0 0 0 1px rgba(255, 255, 255, 0.1) !important;
}
/* Add a subtle gradient overlay */
#service-details::before {
content: '';
position: absolute;
top: 0;
left: 0;
right: 0;
bottom: 0;
background: radial-gradient(ellipse at top left, rgba(255, 255, 255, 0.1) 0%, transparent 50%);
pointer-events: none;
border-radius: 12px;
}
/* Ensure content is above the overlay */
#service-details > * {
position: relative;
z-index: 1;
}
/* Alternative style for browsers without backdrop-filter */
@supports not (backdrop-filter: blur(20px)) {
#service-details {
background:
linear-gradient(135deg, rgba(255, 255, 255, 0.2) 0%, rgba(255, 255, 255, 0.1) 100%),
linear-gradient(135deg, #5865F2 0%, #4752C4 100%) !important;
background-blend-mode: soft-light !important;
}
}
@media (max-width: 768px) {
#service-details {
padding: 1rem;
}
#service-features {
font-size: 0.9rem;
gap: 1rem;
}
#prev-service, #next-service {
width: 35px;
height: 35px;
font-size: 1rem;
}
#rotating-text {
min-width: 200px !important;
max-width: 250px !important;
}
}
@media (max-width: 480px) {
#prev-service, #next-service {
width: 30px;
height: 30px;
font-size: 0.9rem;
}
#service-features {
flex-direction: column;
gap: 0.5rem;
}
}
</style>
<script>
// Interactive service selector
(function() {
const services = [
{
name: "Discord bots",
title: "Discord Bot Development",
description: "Custom Discord bots tailored to your community's needs. From moderation tools to interactive games, we build scalable solutions that enhance engagement.",
features: ["Custom Commands", "Auto-moderation", "24/7 Uptime"]
},
{
name: "community",
title: "Community Management Strategy",
description: "Strategic guidance to grow and nurture thriving online communities. We help you create welcoming spaces that foster meaningful connections.",
features: ["Growth Strategy", "Moderation Plans", "Engagement Tactics"]
},
{
name: "web applications",
title: "Web Application Development",
description: "Modern, responsive web applications built with cutting-edge technologies. From simple sites to complex platforms, we deliver quality solutions.",
features: ["Responsive Design", "Fast Performance", "SEO Optimized"]
},
{
name: "mentorship",
title: "Mentorship & Guidance",
description: "Personalized mentorship for developers at any stage. We provide support, code reviews, and career guidance to help you reach your goals.",
features: ["1-on-1 Sessions", "Code Reviews", "Career Advice"]
},
{
name: "API integration",
title: "API Integration",
description: "Seamless integration with third-party services and APIs. We handle the complex technical work so you can focus on your business.",
features: ["RESTful APIs", "Webhook Setup", "Data Sync"]
},
{
name: "documentation",
title: "Technical Documentation",
description: "Clear, comprehensive documentation that makes your projects accessible. We create guides that developers actually want to read.",
features: ["API Docs", "User Guides", "Code Examples"]
},
{
name: "open-source work",
title: "Open-Source Contributions",
description: "Contributing to and maintaining open-source projects. We help you give back to the community while building your reputation.",
features: ["Bug Fixes", "Feature Development", "Code Maintenance"]
},
{
name: "inclusion",
title: "Inclusive Community Building",
description: "Creating safe, welcoming spaces for all. We specialize in building communities that celebrate diversity and foster belonging.",
features: ["Code of Conduct", "Inclusive Policies", "Accessibility Focus"]
}
];
let currentIndex = 0;
let autoRotateInterval;
let isPaused = false;
const container = document.getElementById('rotating-text');
const prevButton = document.getElementById('prev-service');
const nextButton = document.getElementById('next-service');
const serviceTitle = document.getElementById('service-title');
const serviceDescription = document.getElementById('service-description');
const serviceFeatures = document.getElementById('service-features');
const dotsContainer = document.getElementById('service-dots');
// Create dots
services.forEach((_, index) => {
const dot = document.createElement('button');
dot.className = 'service-dot';
dot.setAttribute('aria-label', `Go to service ${index + 1}`);
dot.addEventListener('click', () => goToService(index));
dotsContainer.appendChild(dot);
});
const dots = dotsContainer.querySelectorAll('.service-dot');
// Create all option elements
container.innerHTML = services.map((service, index) => {
const fontSize = calculateFontSize(service.name);
return `<span class="rotating-option" style="position: absolute; width: 100%; left: 0; top: 50%; transform: translateY(${index === 0 ? '-50%' : 'calc(-50% + 20px)'}); opacity: ${index === 0 ? '1' : '0'}; transition: all 0.5s ease; text-align: center; font-size: ${fontSize}rem; line-height: 1;">${service.name}</span>`;
}).join('');
const optionElements = container.querySelectorAll('.rotating-option');
function calculateFontSize(text, isMobile = false) {
const baseSize = 1.6; // rem - slightly larger base since texts are shorter
const mobileMultiplier = 0.85;
const length = text.length;
let size;
// Adjusted for shorter text lengths
if (length <= 12) {
size = baseSize;
} else if (length <= 15) {
size = baseSize * 0.95;
} else if (length <= 18) {
size = baseSize * 0.9;
} else if (length <= 22) {
size = baseSize * 0.85;
} else {
size = baseSize * 0.8;
}
// Check if mobile
const viewportWidth = window.innerWidth;
if (viewportWidth <= 768 || isMobile) {
size *= mobileMultiplier;
}
return size;
}
function updateServiceDetails() {
const service = services[currentIndex];
serviceTitle.textContent = service.title;
serviceDescription.textContent = service.description;
serviceFeatures.innerHTML = service.features.map(feature =>
`<span style="display: flex; align-items: center; gap: 0.5rem;"><i class="fas fa-check-circle" style="color: #ffd700;"></i> ${feature}</span>`
).join('');
// Update dots
dots.forEach((dot, index) => {
dot.classList.toggle('active', index === currentIndex);
});
// Update font size for the current option
const fontSize = calculateFontSize(service.name);
optionElements[currentIndex].style.fontSize = `${fontSize}rem`;
}
function goToService(index) {
// Fade out current
optionElements[currentIndex].style.opacity = '0';
optionElements[currentIndex].style.transform = 'translateY(calc(-50% - 20px))';
// Update index
currentIndex = index;
// Calculate font size for new service
const newService = services[currentIndex];
const fontSize = calculateFontSize(newService.name);
// Fade in next
setTimeout(() => {
optionElements.forEach((el, idx) => {
if (idx === currentIndex) {
el.style.opacity = '1';
el.style.transform = 'translateY(-50%)';
el.style.fontSize = `${fontSize}rem`;
} else {
el.style.transform = 'translateY(calc(-50% + 20px))';
}
});
updateServiceDetails();
}, 250);
// Reset auto-rotation
if (!isPaused) {
clearInterval(autoRotateInterval);
startAutoRotate();
}
}
function nextService() {
goToService((currentIndex + 1) % services.length);
}
function prevService() {
goToService((currentIndex - 1 + services.length) % services.length);
}
function startAutoRotate() {
autoRotateInterval = setInterval(() => {
if (!isPaused) {
nextService();
}
}, 4000);
}
// Event listeners
prevButton.addEventListener('click', prevService);
nextButton.addEventListener('click', nextService);
// Pause on hover
const section = document.querySelector('#serve-you').parentElement;
section.addEventListener('mouseenter', () => {
isPaused = true;
});
section.addEventListener('mouseleave', () => {
isPaused = false;
});
// Touch support for mobile
container.addEventListener('click', nextService);
// Initialize
updateServiceDetails();
dots[0].classList.add('active');
// Handle window resize
let resizeTimeout;
window.addEventListener('resize', () => {
clearTimeout(resizeTimeout);
resizeTimeout = setTimeout(() => {
// Recalculate font size for current service
const currentService = services[currentIndex];
const newSize = calculateFontSize(currentService.name);
optionElements[currentIndex].style.fontSize = `${newSize}rem`;
}, 250);
});
// Start auto-rotation after a delay
setTimeout(startAutoRotate, 2000);
})();
</script>
<!--
MARK: Client Timeline
-->