Skip to content

Commit aecc3a5

Browse files
committed
Add section for the service offerings
1 parent 3108b76 commit aecc3a5

1 file changed

Lines changed: 156 additions & 16 deletions

File tree

src/pages/index.astro

Lines changed: 156 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -40,12 +40,12 @@ import LogoPattern from "../assets/logo-pattern.png";
4040
<div class="mx-auto max-w-7xl">
4141
<div class="flex flex-col items-center justify-between lg:flex-row">
4242
<div class="mb-8 text-center lg:mb-0 lg:w-1/2 lg:text-left">
43-
<h1 class="mb-6 text-4xl font-bold text-white md:text-6xl">
44-
Web and Blockchain<br />Development Agency
43+
<h1 class="text-4xl md:text-6xl font-bold mb-6 text-white">
44+
Software Development Partner
4545
</h1>
4646
<p class="mb-8 text-xl leading-relaxed text-gray-300 md:text-2xl">
47-
Our fully remote developer team can help<br />
48-
you spot problems early and ship sooner
47+
Plan, build, and scale your software with a senior partner.<br />
48+
From discovery to delivery, we integrate with your team and ship reliably.
4949
</p>
5050
<div class="flex flex-wrap justify-center gap-4 lg:justify-start">
5151
<a
@@ -66,6 +66,123 @@ import LogoPattern from "../assets/logo-pattern.png";
6666
</div>
6767
</section>
6868

69+
<!-- Services Section (selector + detail) -->
70+
<section id="services" class="bg-gray-900 py-16">
71+
<div class="mx-auto max-w-7xl px-4 sm:px-6 lg:px-8">
72+
<div class="mb-12 text-center">
73+
<h2 class="mb-4 text-3xl font-bold md:text-4xl">What We Do</h2>
74+
<p class="text-lg text-gray-300">Pragmatic engineering to ship, scale, and sustain products</p>
75+
</div>
76+
77+
<div class="grid gap-8 md:grid-cols-4">
78+
<!-- Selector -->
79+
<div class="md:col-span-1">
80+
<div role="tablist" aria-label="Services" class="flex flex-col gap-2">
81+
<button data-service-button="web" role="tab" aria-selected="true" class="cursor-pointer rounded-lg border border-gray-700 px-4 py-3 text-left text-gray-200 hover:border-blue-500 hover:text-white focus:outline-none focus:ring-2 focus:ring-blue-600">
82+
Web Applications
83+
</button>
84+
<button data-service-button="extensions" role="tab" aria-selected="false" class="cursor-pointer rounded-lg border border-gray-700 px-4 py-3 text-left text-gray-200 hover:border-blue-500 hover:text-white focus:outline-none focus:ring-2 focus:ring-blue-600">
85+
Niche Extensions
86+
</button>
87+
<button data-service-button="ai" role="tab" aria-selected="false" class="cursor-pointer rounded-lg border border-gray-700 px-4 py-3 text-left text-gray-200 hover:border-blue-500 hover:text-white focus:outline-none focus:ring-2 focus:ring-blue-600">
88+
AI & LLM Apps
89+
</button>
90+
<button data-service-button="blockchain" role="tab" aria-selected="false" class="cursor-pointer rounded-lg border border-gray-700 px-4 py-3 text-left text-gray-200 hover:border-blue-500 hover:text-white focus:outline-none focus:ring-2 focus:ring-blue-600">
91+
Blockchain & Smart Contracts
92+
</button>
93+
<button data-service-button="legacy" role="tab" aria-selected="false" class="cursor-pointer rounded-lg border border-gray-700 px-4 py-3 text-left text-gray-200 hover:border-blue-500 hover:text-white focus:outline-none focus:ring-2 focus:ring-blue-600">
94+
Legacy System Recovery
95+
</button>
96+
<button data-service-button="cost" role="tab" aria-selected="false" class="cursor-pointer rounded-lg border border-gray-700 px-4 py-3 text-left text-gray-200 hover:border-blue-500 hover:text-white focus:outline-none focus:ring-2 focus:ring-blue-600">
97+
Cost Optimization
98+
</button>
99+
</div>
100+
</div>
101+
102+
<!-- Detail -->
103+
<div class="md:col-span-3">
104+
<div class="rounded-lg bg-gray-800 p-8 shadow-lg">
105+
<div data-service-panel="web">
106+
<h3 class="mb-3 text-2xl font-bold text-white">Web Applications</h3>
107+
<p class="text-gray-300">
108+
Product discovery, architecture, and implementation of robust web apps using modern frameworks.
109+
We focus on clear domain models, great UX, and maintainable code.
110+
</p>
111+
<ul class="mt-6 grid list-disc gap-2 pl-5 text-gray-300">
112+
<li>End-to-end feature delivery</li>
113+
<li>APIs and integrations</li>
114+
<li>Performance and accessibility</li>
115+
</ul>
116+
</div>
117+
118+
<div data-service-panel="extensions" class="hidden">
119+
<h3 class="mb-3 text-2xl font-bold text-white">Niche Extensions</h3>
120+
<p class="text-gray-300">
121+
We have a deep experience developing niche extensions, including Adobe Illustrator and Chrome extensions, we are keen to expand our portfolio to other niche extensions.
122+
</p>
123+
<ul class="mt-6 grid list-disc gap-2 pl-5 text-gray-300">
124+
<li>Manifest V3 ready</li>
125+
<li>Content scripts and messaging</li>
126+
<li>Publishing and updates</li>
127+
</ul>
128+
</div>
129+
130+
<div data-service-panel="ai" class="hidden">
131+
<h3 class="mb-3 text-2xl font-bold text-white">AI & LLM Apps</h3>
132+
<p class="text-gray-300">
133+
Production-ready AI capabilities: retrieval, agents, evals, and observability integrated into your product.
134+
</p>
135+
<ul class="mt-6 grid list-disc gap-2 pl-5 text-gray-300">
136+
<li>RAG pipelines and embeddings</li>
137+
<li>Tool-using agents and workflows</li>
138+
<li>Voice-powered assistants</li>
139+
</ul>
140+
</div>
141+
142+
<div data-service-panel="blockchain" class="hidden">
143+
<h3 class="mb-3 text-2xl font-bold text-white">Blockchain & Smart Contracts</h3>
144+
<p class="text-gray-300">
145+
Practical on-chain solutions with off-chain services when needed. Security-minded reviews and
146+
testable contracts with clean deployment workflows.
147+
</p>
148+
<ul class="mt-6 grid list-disc gap-2 pl-5 text-gray-300">
149+
<li>Contract design and audits</li>
150+
<li>Indexing and data pipelines</li>
151+
<li>Wallet and dApp integration</li>
152+
</ul>
153+
</div>
154+
155+
<div data-service-panel="legacy" class="hidden">
156+
<h3 class="mb-3 text-2xl font-bold text-white">Legacy System Recovery</h3>
157+
<p class="text-gray-300">
158+
Stabilize, document, and incrementally modernize critical systems without halting business. We
159+
reduce risk with small, measurable steps.
160+
</p>
161+
<ul class="mt-6 grid list-disc gap-2 pl-5 text-gray-300">
162+
<li>Readability and tests first</li>
163+
<li>Strangler-fig migrations</li>
164+
<li>Observability and error budgets</li>
165+
</ul>
166+
</div>
167+
168+
<div data-service-panel="cost" class="hidden">
169+
<h3 class="mb-3 text-2xl font-bold text-white">Cost Optimization</h3>
170+
<p class="text-gray-300">
171+
Measure first, then optimize. We tune infrastructure and code paths to cut spend while keeping
172+
reliability and user experience intact.
173+
</p>
174+
<ul class="mt-6 grid list-disc gap-2 pl-5 text-gray-300">
175+
<li>Profiling and benchmarks</li>
176+
<li>Cloud architecture reviews</li>
177+
<li>Caching and query tuning</li>
178+
</ul>
179+
</div>
180+
</div>
181+
</div>
182+
</div>
183+
</div>
184+
</section>
185+
69186
<!-- Featured Blog Posts -->
70187
<section id="blog" class="bg-gray-800 py-16">
71188
<div class="mx-auto max-w-7xl px-4 sm:px-6 lg:px-8">
@@ -179,7 +296,7 @@ import LogoPattern from "../assets/logo-pattern.png";
179296
<div class="swiper-wrapper">
180297
{
181298
testimonials.map((testimonial, index) => {
182-
const fullText = testimonial.body;
299+
const fullText = testimonial.body || "";
183300
const isLong = fullText.length > 200;
184301
const truncatedText = isLong
185302
? fullText.substring(0, 200).trim()
@@ -284,12 +401,39 @@ import LogoPattern from "../assets/logo-pattern.png";
284401
});
285402
});
286403

287-
// Load Swiper JS and initialize
404+
// Tabs for services (no external deps)
405+
const serviceButtons = document.querySelectorAll<HTMLButtonElement>('[data-service-button]');
406+
const servicePanels = document.querySelectorAll<HTMLElement>('[data-service-panel]');
407+
const activateService = (id: string) => {
408+
serviceButtons.forEach((btn) => {
409+
const active = btn.getAttribute('data-service-button') === id;
410+
btn.setAttribute('aria-selected', active ? 'true' : 'false');
411+
btn.classList.toggle('border-blue-500', active);
412+
btn.classList.toggle('text-white', active);
413+
});
414+
servicePanels.forEach((panel) => {
415+
const show = panel.getAttribute('data-service-panel') === id;
416+
panel.classList.toggle('hidden', !show);
417+
});
418+
};
419+
// Default selection
420+
const firstBtn = document.querySelector<HTMLButtonElement>('[data-service-button]');
421+
if (firstBtn) {
422+
const id = firstBtn.getAttribute('data-service-button');
423+
if (id) activateService(id);
424+
}
425+
serviceButtons.forEach((btn) =>
426+
btn.addEventListener('click', () => {
427+
const id = btn.getAttribute('data-service-button');
428+
if (id) activateService(id);
429+
})
430+
);
431+
432+
// Load Swiper JS and initialize (for testimonials/blog only)
288433
const swiperScript = document.createElement("script");
289434
swiperScript.src =
290435
"https://cdn.jsdelivr.net/npm/swiper@11/swiper-bundle.min.js";
291436
swiperScript.onload = () => {
292-
// Initialize Swipers after script is loaded
293437
// Testimonials Swiper
294438
// @ts-ignore - Swiper provided by CDN
295439
const testimonialsSwiper = new Swiper(".testimonials-swiper", {
@@ -309,13 +453,10 @@ import LogoPattern from "../assets/logo-pattern.png";
309453
prevEl: ".testimonials-swiper .swiper-button-prev",
310454
},
311455
breakpoints: {
312-
768: {
313-
slidesPerView: 1,
314-
},
456+
768: { slidesPerView: 1 },
315457
},
316458
});
317459

318-
// Blog posts Swiper
319460
// Blog posts Swiper
320461
// @ts-ignore - Swiper provided by CDN
321462
const blogSwiper = new Swiper(".blogposts-swiper", {
@@ -346,12 +487,11 @@ import LogoPattern from "../assets/logo-pattern.png";
346487

347488
toggles.forEach((toggle) => {
348489
toggle.addEventListener("click", () => {
349-
const textElement = toggle.previousElementSibling;
490+
const textElement = toggle.previousElementSibling as HTMLElement | null;
491+
if (!textElement) return;
350492
const isExpanded = toggle.getAttribute("data-expanded") === "true";
351-
const fullText = textElement.getAttribute("data-full-text");
352-
const truncatedText = textElement.getAttribute(
353-
"data-truncated-text",
354-
);
493+
const fullText = textElement.getAttribute("data-full-text") || "";
494+
const truncatedText = textElement.getAttribute("data-truncated-text") || "";
355495

356496
if (isExpanded) {
357497
textElement.textContent = truncatedText;

0 commit comments

Comments
 (0)