Files
365devnet/src/pages/[lang]/index.astro
Richard Bergsma f7645b7b25 Update dependencies, enhance security headers, and add brand information to translations
- Updated various dependencies in package.json and package-lock.json for improved performance and security.
- Changed Cross-Origin-Embedder-Policy from 'require-corp' to 'credentialless' in server.js and nginx.conf for better compatibility.
- Enhanced Content-Security-Policy to include specific domains for script and connect sources.
- Added brand information to translations for multiple languages, improving localization and user experience.
- Introduced a new BrandMarquee component in the homepage layout to showcase brands effectively.
2025-11-04 23:35:04 +01:00

728 lines
20 KiB
Plaintext

---
export const prerender = true;
import Layout from '~/layouts/PageLayout.astro';
import Hero from '~/components/widgets/Hero2.astro';
import BrandMarquee from '~/components/widgets/BrandMarquee.astro';
import Features from '~/components/widgets/Features.astro';
import Content from '~/components/widgets/Content.astro';
import CallToAction from '~/components/widgets/CallToAction.astro';
import Contact from '~/components/widgets/Contact.astro';
import { getTranslation, supportedLanguages } from '~/i18n/translations';
import { getExplosiveHomepageTranslation } from '~/i18n/translations.homepage.ts';
import OurCommitmentImage from '~/assets/images/OurCommitment.webp';
import HomepageIntroImage from '~/assets/images/HomepageIntroImage.webp';
export async function getStaticPaths() {
return supportedLanguages.map((lang) => ({
params: { lang },
}));
}
const { lang } = Astro.params;
if (!supportedLanguages.includes(lang)) {
return Astro.redirect('/en/');
}
const t = getTranslation(lang);
const explosive = getExplosiveHomepageTranslation(lang);
const metadata = {
title: 'IT Systems & Automation for Businesses | Power Automate & Microsoft 365 Expert',
description: 'Transform your business with expert IT automation solutions. Specializing in Power Automate, Microsoft 365, SharePoint, and custom API integrations for enhanced productivity and efficiency.'
};
---
<style>
/* Explosive hero background with neon vibes */
.hero-explosive {
background:
radial-gradient(circle at 20% 80%, #ff006e 0%, transparent 50%),
radial-gradient(circle at 80% 20%, #8338ec 0%, transparent 50%),
radial-gradient(circle at 40% 40%, #3a86ff 0%, transparent 50%),
linear-gradient(135deg, #06ffa5 0%, #ff006e 25%, #8338ec 50%, #3a86ff 75%, #06ffa5 100%);
background-size: 300% 300%, 250% 250%, 400% 400%, 600% 600%;
animation: explosiveGradient 15s ease infinite;
position: relative;
overflow: hidden;
}
/* Prefer reduced motion and mobile fallback for heavy animation */
@media (max-width: 768px) {
.hero-explosive {
animation: none;
background-size: 200% 200%, 200% 200%, 200% 200%, 300% 300%;
}
.floating-orbs { display: none; }
}
@media (prefers-reduced-motion: reduce) {
.hero-explosive { animation: none; }
.orb { animation: none; }
}
/* Floating orbs with vivid colors */
.floating-orbs {
position: absolute;
top: 0;
left: 0;
width: 100%;
height: 100%;
pointer-events: none;
overflow: hidden;
}
.orb {
position: absolute;
border-radius: 50%;
filter: blur(2px);
animation: orbFloat 20s infinite ease-in-out;
}
.orb-1 {
width: 150px;
height: 150px;
background: radial-gradient(circle, #ff006e, #ff6b9d);
top: 10%;
left: 15%;
animation-delay: 0s;
box-shadow: 0 0 30px rgba(255, 0, 110, 0.3);
}
.orb-2 {
width: 200px;
height: 200px;
background: radial-gradient(circle, #8338ec, #a663cc);
top: 70%;
right: 10%;
animation-delay: -7s;
box-shadow: 0 0 40px rgba(131, 56, 236, 0.3);
}
.orb-3 {
width: 120px;
height: 120px;
background: radial-gradient(circle, #3a86ff, #72b4ff);
bottom: 30%;
left: 70%;
animation-delay: -14s;
box-shadow: 0 0 25px rgba(58, 134, 255, 0.3);
}
.orb-4 {
width: 180px;
height: 180px;
background: radial-gradient(circle, #06ffa5, #59ffb8);
top: 40%;
left: 5%;
animation-delay: -10s;
box-shadow: 0 0 35px rgba(6, 255, 165, 0.3);
}
.orb-5 {
width: 100px;
height: 100px;
background: radial-gradient(circle, #ffbe0b, #ffd23f);
top: 20%;
right: 30%;
animation-delay: -3s;
box-shadow: 0 0 20px rgba(255, 190, 11, 0.3);
}
@keyframes explosiveGradient {
0%, 100% { background-position: 0% 0%, 0% 0%, 0% 0%, 0% 50%; }
25% { background-position: 100% 100%, 50% 50%, 25% 75%, 100% 50%; }
50% { background-position: 50% 25%, 100% 0%, 75% 25%, 50% 100%; }
75% { background-position: 25% 75%, 25% 100%, 50% 50%, 0% 50%; }
}
@keyframes orbFloat {
0%, 100% {
transform: translateY(0px) translateX(0px) scale(1);
opacity: 0.6;
}
25% {
transform: translateY(-60px) translateX(40px) scale(1.2);
opacity: 0.8;
}
50% {
transform: translateY(-30px) translateX(-20px) scale(0.9);
opacity: 0.7;
}
75% {
transform: translateY(-80px) translateX(60px) scale(1.1);
opacity: 0.9;
}
}
/* Vibrant glass cards */
:global(.glass-vibrant) {
background: rgba(255, 255, 255, 0.1) !important;
backdrop-filter: blur(30px) !important;
border: 2px solid rgba(255, 255, 255, 0.2) !important;
box-shadow:
0 25px 45px rgba(0, 0, 0, 0.1),
0 0 0 1px rgba(255, 255, 255, 0.1) inset,
0 0 60px rgba(102, 126, 234, 0.3) !important;
transition: all 0.4s cubic-bezier(0.4, 0, 0.2, 1) !important;
border-radius: 32px !important;
position: relative;
overflow: hidden;
}
:global(.glass-vibrant::before) {
content: '';
position: absolute;
top: 0;
left: 0;
right: 0;
bottom: 0;
background: linear-gradient(135deg,
rgba(255, 0, 110, 0.1) 0%,
rgba(131, 56, 236, 0.1) 25%,
rgba(58, 134, 255, 0.1) 50%,
rgba(6, 255, 165, 0.1) 75%,
rgba(255, 190, 11, 0.1) 100%);
opacity: 0;
transition: opacity 0.4s ease;
pointer-events: none;
}
:global(.glass-vibrant:hover::before) {
opacity: 1;
}
:global(.glass-vibrant:hover) {
box-shadow:
0 40px 80px rgba(0, 0, 0, 0.2),
0 0 0 2px rgba(255, 255, 255, 0.2) inset,
0 0 100px rgba(102, 126, 234, 0.5) !important;
}
/* Dark mode vibrant */
:global(.dark .glass-vibrant) {
background: rgba(0, 0, 0, 0.3) !important;
border-color: rgba(255, 255, 255, 0.2) !important;
box-shadow:
0 25px 45px rgba(0, 0, 0, 0.4),
0 0 0 1px rgba(255, 255, 255, 0.1) inset,
0 0 60px rgba(131, 56, 236, 0.4) !important;
}
:global(.dark .glass-vibrant:hover) {
box-shadow:
0 40px 80px rgba(0, 0, 0, 0.6),
0 0 0 2px rgba(255, 255, 255, 0.2) inset,
0 0 100px rgba(131, 56, 236, 0.6) !important;
}
/* Refined text effects */
.neon-title {
font-size: clamp(3rem, 8vw, 6rem);
font-weight: 900;
background: linear-gradient(135deg,
#ff006e 0%,
#8338ec 25%,
#3a86ff 50%,
#06ffa5 75%,
#ffbe0b 100%);
background-size: 300% 300%;
-webkit-background-clip: text;
-webkit-text-fill-color: transparent;
background-clip: text;
animation: neonPulse 4s ease-in-out infinite alternate;
letter-spacing: -0.02em;
line-height: 1.1;
margin-bottom: 2rem;
padding-left: 2rem;
}
.neon-subtitle {
font-size: 1.5rem;
font-weight: 600;
color: white;
text-shadow: 0 2px 10px rgba(255, 255, 255, 0.3);
margin-bottom: 3rem;
line-height: 1.4;
max-width: 800px;
padding-left: 2rem;
}
/* Proper light mode fixes using html class */
html:not(.dark) .neon-subtitle {
color: rgba(15, 23, 42, 0.9) !important;
text-shadow: 0 2px 10px rgba(0, 0, 0, 0.1) !important;
}
@keyframes neonPulse {
0% {
background-position: 0% 50%;
}
100% {
background-position: 100% 50%;
}
}
/* Refined CTA buttons */
.cta-explosive {
background: linear-gradient(135deg, #ff006e, #8338ec, #3a86ff);
background-size: 300% 300%;
color: white;
padding: 1.2rem 3rem;
border-radius: 60px;
text-decoration: none;
font-weight: 700;
font-size: 1.2rem;
transition: all 0.4s cubic-bezier(0.4, 0, 0.2, 1);
box-shadow: 0 8px 25px rgba(255, 0, 110, 0.25);
border: none;
position: relative;
overflow: hidden;
text-transform: uppercase;
letter-spacing: 1px;
margin-left: 2rem;
}
.cta-explosive::before {
content: '';
position: absolute;
top: 0;
left: -100%;
width: 100%;
height: 100%;
background: linear-gradient(90deg, transparent, rgba(255, 255, 255, 0.4), transparent);
transition: left 0.6s;
}
.cta-explosive:hover::before {
left: 100%;
}
.cta-explosive:hover {
transform: translateY(-3px) scale(1.05);
box-shadow: 0 15px 35px rgba(255, 0, 110, 0.4);
background-position: 100% 50%;
}
.cta-secondary-explosive {
background: rgba(255, 255, 255, 0.1);
backdrop-filter: blur(20px);
color: white;
padding: 1.2rem 3rem;
border-radius: 60px;
text-decoration: none;
font-weight: 700;
font-size: 1.2rem;
border: 2px solid rgba(6, 255, 165, 0.4);
transition: all 0.4s cubic-bezier(0.4, 0, 0.2, 1);
text-transform: uppercase;
letter-spacing: 1px;
margin-left: 2rem;
/* Override any conflicting base button styles */
text-shadow: 0 1px 2px rgba(0, 0, 0, 0.1);
}
.cta-secondary-explosive:hover {
background: rgba(6, 255, 165, 0.15);
transform: translateY(-2px) scale(1.03);
border-color: rgba(6, 255, 165, 0.6);
color: white;
}
/* Light mode CTA fixes - enhanced for better visibility */
html:not(.dark) .cta-secondary-explosive {
background: rgba(255, 255, 255, 0.95) !important;
color: rgba(15, 23, 42, 1) !important;
border-color: rgba(6, 255, 165, 0.7) !important;
text-shadow: none !important;
box-shadow: 0 4px 15px rgba(0, 0, 0, 0.1) !important;
}
html:not(.dark) .cta-secondary-explosive:hover {
background: rgba(6, 255, 165, 0.15) !important;
color: rgba(15, 23, 42, 1) !important;
border-color: rgba(6, 255, 165, 0.8) !important;
box-shadow: 0 6px 20px rgba(6, 255, 165, 0.2) !important;
}
/* Light mode content card fixes */
html:not(.dark) .light-mode-card {
background: rgba(255, 255, 255, 0.8) !important;
border-color: rgba(0, 0, 0, 0.1) !important;
}
html:not(.dark) .method-title {
color: rgba(15, 23, 42, 0.9) !important;
}
html:not(.dark) .method-description {
color: rgba(75, 85, 99, 0.9) !important;
}
html:not(.dark) .method-highlights {
color: rgba(15, 23, 42, 0.8) !important;
}
/* Light mode CTA section fixes */
html:not(.dark) .cta-subtitle {
color: rgba(15, 23, 42, 0.9) !important;
}
@keyframes ctaGlow {
0% { box-shadow: 0 8px 25px rgba(255, 0, 110, 0.25); }
100% { box-shadow: 0 8px 25px rgba(58, 134, 255, 0.35); }
}
/* Service cards with color coding */
.service-card {
position: relative;
overflow: hidden;
}
.service-card-1::before { background: linear-gradient(135deg, rgba(255, 0, 110, 0.2), rgba(255, 107, 157, 0.1)); }
.service-card-2::before { background: linear-gradient(135deg, rgba(131, 56, 236, 0.2), rgba(166, 99, 204, 0.1)); }
.service-card-3::before { background: linear-gradient(135deg, rgba(58, 134, 255, 0.2), rgba(114, 180, 255, 0.1)); }
.service-card-4::before { background: linear-gradient(135deg, rgba(6, 255, 165, 0.2), rgba(89, 255, 184, 0.1)); }
.service-card-5::before { background: linear-gradient(135deg, rgba(255, 190, 11, 0.2), rgba(255, 210, 63, 0.1)); }
.service-card-6::before { background: linear-gradient(135deg, rgba(255, 87, 108, 0.2), rgba(255, 154, 158, 0.1)); }
.service-card::before {
content: '';
position: absolute;
top: 0;
left: 0;
right: 0;
bottom: 0;
opacity: 0;
transition: opacity 0.3s ease;
pointer-events: none;
}
.service-card:hover::before {
opacity: 1;
}
/* Section backgrounds with gradients */
.section-gradient-1 {
background: linear-gradient(135deg,
rgba(255, 0, 110, 0.05) 0%,
rgba(131, 56, 236, 0.05) 50%,
rgba(58, 134, 255, 0.05) 100%);
}
.section-gradient-2 {
background: linear-gradient(135deg,
rgba(6, 255, 165, 0.05) 0%,
rgba(255, 190, 11, 0.05) 50%,
rgba(255, 87, 108, 0.05) 100%);
}
.section-gradient-3 {
background: linear-gradient(135deg,
rgba(58, 134, 255, 0.05) 0%,
rgba(131, 56, 236, 0.05) 50%,
rgba(255, 0, 110, 0.05) 100%);
}
/* Content spacing */
.content-section {
margin: 8rem 0;
position: relative;
padding: 4rem 0;
}
.content-section:first-of-type {
margin-top: 0;
}
.content-section:last-of-type {
margin-bottom: 0;
}
/* Animation entrance */
.explosive-entrance {
animation: explosiveSlideUp 1s ease-out forwards;
opacity: 0;
transform: translateY(60px) scale(0.9);
}
.explosive-entrance:nth-child(1) { animation-delay: 0.1s; }
.explosive-entrance:nth-child(2) { animation-delay: 0.3s; }
.explosive-entrance:nth-child(3) { animation-delay: 0.5s; }
.explosive-entrance:nth-child(4) { animation-delay: 0.7s; }
@keyframes explosiveSlideUp {
to {
opacity: 1;
transform: translateY(0) scale(1);
}
}
/* Hero full screen */
.hero-fullscreen {
min-height: 100vh;
display: flex;
align-items: center;
position: relative;
}
/* Responsive */
@media (max-width: 768px) {
.neon-title {
font-size: clamp(2rem, 8vw, 4rem);
padding-left: 1rem;
}
.neon-subtitle {
font-size: 1.2rem;
padding-left: 1rem;
}
.content-section {
margin: 5rem 0;
padding: 2rem 0;
}
.cta-explosive,
.cta-secondary-explosive {
padding: 1rem 2rem;
font-size: 1rem;
margin-left: 1rem;
}
.cta-subtitle {
font-size: 1.1rem !important;
}
}
</style>
<Layout metadata={metadata}>
<!-- Explosive Hero Section -->
<div class="hero-fullscreen">
<Hero
isDark={false}
actions={[
{
variant: 'primary',
text: explosive.actions.learnMore,
href: '#services',
},
{
text: explosive.actions.contactMe,
href: '#contact',
variant: 'secondary'
},
]}
image={{
src: HomepageIntroImage,
alt: 'IT Automation Revolution',
loading: 'eager',
}}
>
<Fragment slot="bg">
<div class="hero-explosive">
<div class="floating-orbs">
<div class="orb orb-1"></div>
<div class="orb orb-2"></div>
<div class="orb orb-3"></div>
<div class="orb orb-4"></div>
<div class="orb orb-5"></div>
</div>
</div>
</Fragment>
<Fragment slot="title">
<div class="neon-title">
{explosive.hero.title}
</div>
</Fragment>
<Fragment slot="subtitle">
<div class="neon-subtitle">
{explosive.hero.subtitle}
</div>
</Fragment>
</Hero>
</div>
<!-- Brand Marquee -->
<BrandMarquee
title={explosive.brands?.title || t.homepage?.brands?.title || 'Our Brands'}
subtitle={explosive.brands?.subtitle || t.homepage?.brands?.subtitle || 'Part of the 365DevNet ecosystem'}
speed="normal"
brands={[
{
name: '365DevNet',
icon: 'tabler:code',
description: explosive.brands?.devnet || t.homepage?.brands?.devnet || 'Development Solutions',
link: `/${lang}`,
},
{
name: 'Tiber365',
icon: 'tabler:bulb',
description: explosive.brands?.tiber || t.homepage?.brands?.tiber || 'IT Consultancy',
link: `/${lang}/bergsma`,
},
{
name: 'Bergsma.it',
icon: 'tabler:chart-line',
description: explosive.brands?.bergsma || t.homepage?.brands?.bergsma || 'Business Consultancy',
link: `/${lang}/bergsma`,
},
{
name: 'SyncEra',
icon: 'tabler:activity',
description: explosive.brands?.syncera || t.homepage?.brands?.syncera || 'Health & Fitness Sync',
link: `/${lang}/syncera`,
},
{
name: 'Journii',
icon: 'tabler:map-pin',
description: explosive.brands?.journii || t.homepage?.brands?.journii || 'Travel & Journaling',
link: `/${lang}/journii`,
},
]}
/>
<!-- Services with Color Explosions -->
<div id="services" class="content-section section-gradient-1 explosive-entrance">
<Features
id="services"
tagline={explosive.services.tagline}
title={explosive.services.title}
subtitle={explosive.services.subtitle}
items={explosive.services.items.map((item, index) => ({
title: item.title,
description: item.description,
icon: [
'tabler:bolt',
'tabler:robot',
'tabler:plug-connected',
'tabler:building-skyscraper',
'tabler:share',
'tabler:shield-check'
][index],
class: `service-card service-card-${index + 1}`
}))}
classes={{
container: 'glass-vibrant'
}}
/>
</div>
<!-- Approach Section with Combined Card -->
<div id="approach" class="content-section section-gradient-2 explosive-entrance">
<Content
isReversed
tagline={explosive.approach.tagline}
title={explosive.approach.title}
items={[]}
image={{
src: OurCommitmentImage,
alt: 'Results-Driven IT Solutions',
loading: 'lazy',
}}
classes={{
container: 'glass-vibrant'
}}
>
<Fragment slot="content">
<div class="text-xl text-white space-y-8">
<div class="text-2xl font-bold text-transparent bg-clip-text bg-gradient-to-r from-pink-400 to-purple-400 mb-8">
{explosive.approach.expertise}
</div>
<!-- Combined Method Card -->
<div class="bg-black/20 backdrop-blur-lg rounded-2xl p-8 border border-white/10 space-y-6 light-mode-card">
{explosive.approach.methods.map((method, index) => (
<div class="flex items-start space-x-4">
<div class={`w-12 h-12 rounded-full ${
['bg-gradient-to-r from-green-400 to-green-600',
'bg-gradient-to-r from-yellow-400 to-orange-500',
'bg-gradient-to-r from-blue-400 to-purple-500'][index]
} flex items-center justify-center flex-shrink-0`}>
<span class="text-2xl">{['🎯', '⚡', '🔄'][index]}</span>
</div>
<div>
<h3 class="text-xl font-bold text-white mb-2 method-title">{method.title}</h3>
<p class="text-gray-300 method-description">{method.description}</p>
</div>
</div>
))}
</div>
<div class="text-lg pt-4 method-highlights">
{explosive.approach.highlights.split('\n').map((line) => (
<>
{line}
<br />
</>
))}
</div>
</div>
</Fragment>
</Content>
</div>
<!-- Call to Action Explosion -->
<div id="cta" class="content-section section-gradient-3 explosive-entrance">
<CallToAction
callToAction={{
text: explosive.cta.button,
href: '#contact',
icon: 'tabler:rocket',
variant: 'primary'
}}
classes={{
container: 'glass-vibrant'
}}
>
<Fragment slot="title">
<div class="text-3xl sm:text-4xl md:text-5xl lg:text-6xl font-black mb-6">
<span class="text-transparent bg-clip-text bg-gradient-to-r from-pink-400 via-purple-400 to-blue-400">
{explosive.cta.title}
</span>
</div>
</Fragment>
<Fragment slot="subtitle">
<div class="text-2xl text-white font-semibold cta-subtitle">
{explosive.cta.subtitle}
</div>
</Fragment>
</CallToAction>
</div>
<!-- Contact with Personality -->
<div id="contact" class="content-section explosive-entrance">
<Contact
id="contact"
title={explosive.contact.title}
subtitle={explosive.contact.subtitle}
inputs={[
{
type: 'text',
name: 'name',
label: explosive.contact.fields.name,
placeholder: explosive.contact.fields.namePlaceholder,
},
{
type: 'email',
name: 'email',
label: explosive.contact.fields.email,
placeholder: explosive.contact.fields.emailPlaceholder,
},
]}
textarea={{
label: explosive.contact.fields.message,
placeholder: explosive.contact.fields.messagePlaceholder,
rows: 6,
}}
disclaimer={{
label: explosive.contact.disclaimer,
}}
description={explosive.contact.description}
classes={{
container: 'glass-vibrant'
}}
spamReview={explosive.spamReview}
/>
</div>
</Layout>