generated from nhcarrigan/template
feat: set up how can we help section
This commit is contained in:
+409
@@ -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
|
RESPONSIVE DESIGN
|
||||||
============================================ */
|
============================================ */
|
||||||
@@ -725,6 +762,378 @@
|
|||||||
</p>
|
</p>
|
||||||
</section>
|
</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
|
MARK: Client Timeline
|
||||||
-->
|
-->
|
||||||
|
|||||||
Reference in New Issue
Block a user