Skip to content

Commit eb248f9

Browse files
committed
feat: refactor services page to use typed data model and data source
1 parent 54957db commit eb248f9

File tree

4 files changed

+110
-102
lines changed

4 files changed

+110
-102
lines changed

Changelog.md

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@ and this project adheres to [semantic Versioning](https://semver.org/spec/v2.0.0
2525
- UI: Project titles on the Projects page now use the primary theme color for emphasis (`src/pages/projects.astro`).
2626
- UI: Increased language icon size on Projects page to 32px for better readability (`src/pages/projects.astro`).
2727
- Works: Introduced typed data model and data source for Works page (`src/types/works.ts`, `src/data/works.ts`).
28+
- Services: Introduced typed data model and data source (`src/types/services.ts`, `src/data/services.ts`).
2829

2930
### Changed
3031
- Posts listing now renders Markdown formatting for summaries on `/posts` using Astro's Markdown processor; it extracts the first paragraph of the rendered HTML and supports Shiki syntax highlighting (`src/pages/posts/index.astro`).
@@ -55,20 +56,18 @@ and this project adheres to [semantic Versioning](https://semver.org/spec/v2.0.0
5556
- Converted Services testimonials to a continuous marquee-style auto-scroll with pause-on-hover and reduced-motion support (`src/pages/services.astro`).
5657
- Aligned testimonial service names to canonical categories for SEO and schema consistency (`src/pages/services.astro`).
5758
- Works: Rewrote the `Summary` to reflect certifications and DevOps/infra experience more accurately (`src/pages/works.astro`).
58-
- Works: Fixed structure/frontmatter after edit to ensure valid Astro layout and correct section ordering (`src/pages/works.astro`).
5959
- Works: Simplified `Summary` to focus on coding, platform building, automation, networking, and AI; removed certification listing and noted personal aviation goal (`src/pages/works.astro`).
6060
- Home: Updated homepage title/description, subheading, and intro paragraphs to align with Works summary (platforms, automation, networking, AI, aviation goal) (`src/pages/index.astro`).
6161
- Meta: Added explicit page descriptions to improve SEO and social previews on Works and About (`src/pages/works.astro`, `src/pages/about.astro`).
6262
- Works: Added a second paragraph to `Summary` covering homelab/self‑hosting, small tools to reduce toil, reliability/security/cost focus, and collaboration interests (`src/pages/works.astro`).
6363
- Home: Added two more intro paragraphs expanding on tools/self‑hosting/reliability and collaboration interests (`src/pages/index.astro`).
64-
- Home: Updated collaboration line to mirror Services offerings and linked to /services (`src/pages/index.astro`).
65-
- Works: Refactored page to render from typed data source (`src/pages/works.astro`) using `src/data/works.ts`.
64+
- Home: Updated collaboration line to mirror Services offerings and linked to /services (`src/pages/index.astro`).
65+
- Works: Refactored page to render from typed data source (`src/pages/works.astro`) using `src/data/works.ts`.
6666

6767
### Fixed
6868
- Home: Removed stray placeholder and corrected paragraph/container tags causing parse error in the homepage (`src/pages/index.astro`).
6969
- Deleted the unused Webring module directory (`src/ring/`).
7070
- SEO: Converted social images to absolute URLs for more reliable link previews (`src/components/base-head.astro`).
71-
- SEO: Added BreadcrumbList JSON‑LD across pages based on URL path segments (`src/layouts/shell.astro`).
7271
- SEO: Added bullets to document sitemap auto-discovery (`src/pages/sitemap.xml.ts`).
7372
- UX: Default theme is now dark when no saved preference exists (`src/layouts/shell.astro`).
7473
- RSS/Sitemap: Base URL now derived from the incoming request origin to support multiple domains (`src/pages/rss.xml.ts`, `src/pages/sitemap.xml.ts`).

src/data/services.ts

Lines changed: 74 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,74 @@
1+
import type { ServicesData } from '../types/services';
2+
3+
const servicesData: ServicesData = {
4+
services: [
5+
{
6+
name: 'Server Setup & Hardening',
7+
description: 'Provisioning, firewall/TLS, users, backups, and secure defaults on Linux servers.',
8+
features: ['Firewall, TLS, SSH and users', 'Backups & recovery drills', 'Baseline hardening'],
9+
category: 'infrastructure',
10+
},
11+
{
12+
name: 'CI/CD Implementation',
13+
description: 'Build/test/deploy pipelines with GitHub Actions or GitLab CI, environments, and releases.',
14+
features: ['GitHub Actions / GitLab CI', 'Multi‑env deployments', 'Release workflows'],
15+
category: 'devops',
16+
},
17+
{
18+
name: 'Automation with Ansible',
19+
description: 'Playbooks, roles, inventories, idempotent provisioning and repeatable ops.',
20+
features: ['Playbooks & roles', 'Inventories & secrets', 'Server fleet automation'],
21+
category: 'automation',
22+
},
23+
{
24+
name: 'Self‑Hosting & Homelab Consultation',
25+
description: 'Architecture, SSO, backups/restore, monitoring guidance, and safe internet exposure.',
26+
features: ['Reverse proxy & TLS', 'Single‑sign on (SSO)', 'Backups & monitoring guidance'],
27+
category: 'consulting',
28+
},
29+
{
30+
name: 'Website Project Setup (Custom or CMS)',
31+
description: 'From Astro/Next.js custom builds to CMS setups (e.g., WordPress, Ghost) with sensible defaults.',
32+
features: ['Astro / Next.js', 'WordPress / Ghost', 'Content & SEO basics'],
33+
category: 'web',
34+
},
35+
{
36+
name: 'Monitoring Setup (Grafana & Prometheus)',
37+
description: 'Dashboards, alerting, and metrics pipelines for actionable insights.',
38+
features: ['Grafana dashboards & panels', 'Prometheus scraping & exporters', 'Alertmanager routing & notifications'],
39+
category: 'observability',
40+
},
41+
],
42+
testimonials: [
43+
{
44+
quote: 'Jeff helped us set up a firewall at the start of our project. After that we keep consulting with him for any security related issues.',
45+
author: 'Adhy Musaad',
46+
role: 'CTO, Kwikku Interactive',
47+
serviceName: 'Server Setup & Hardening',
48+
rating: 5,
49+
},
50+
{
51+
quote: 'Our website and mail setup was done in a matter of hours. Saved us a lot of time and money.',
52+
author: 'Jason Lim',
53+
role: 'Business Owner',
54+
serviceName: 'Website Project Setup (Custom or CMS)',
55+
rating: 5,
56+
},
57+
{
58+
quote: 'My homelab is messed before. After consulting with Jeff, it is now stable, monitored, and easy to maintain. Thanks a lot!',
59+
author: 'K. Tan',
60+
role: 'Indie Dev',
61+
serviceName: 'Self‑Hosting & Homelab Consultation',
62+
rating: 5,
63+
},
64+
{
65+
quote: 'Jeff helped me set up my website and mail server in a matter of hours. Even though He is my cousin, I still want to give him a big thank you.',
66+
author: 'N. Chen',
67+
role: 'Individual',
68+
serviceName: 'Website Project Setup (Custom or CMS)',
69+
rating: 5,
70+
},
71+
],
72+
};
73+
74+
export default servicesData;

src/pages/services.astro

Lines changed: 14 additions & 98 deletions
Original file line numberDiff line numberDiff line change
@@ -1,49 +1,13 @@
11
---
22
import Shell from '../layouts/shell.astro';
3+
import data from '../data/services';
34
45
// SEO and structured data
56
const site = 'https://skiddle.id';
67
const pageUrl = new URL('/services', site).toString();
78
8-
const servicesData = [
9-
{ name: 'Server Setup & Hardening', description: 'Provisioning, firewall/TLS, users, backups, and secure defaults on Linux servers.' },
10-
{ name: 'CI/CD Implementation', description: 'Build/test/deploy pipelines with GitHub Actions or GitLab CI, environments, and releases.' },
11-
{ name: 'Automation with Ansible', description: 'Playbooks, roles, inventories, idempotent provisioning and repeatable ops.' },
12-
{ name: 'Self‑Hosting & Homelab Consultation', description: 'Architecture, SSO, backups/restore, monitoring guidance, and safe internet exposure.' },
13-
{ name: 'Website Project Setup (Custom or CMS)', description: 'From Astro/Next.js custom builds to CMS setups (e.g., WordPress, Ghost) with sensible defaults.' },
14-
{ name: 'Monitoring Setup (Grafana & Prometheus)', description: 'Dashboards, alerting, and metrics pipelines for actionable insights.' },
15-
];
16-
17-
const testimonials = [
18-
{
19-
quote: 'Jeff helped us set up a firewall at the start of our project. After that we keep consulting with him for any security related issues.',
20-
author: 'Adhy Musaad',
21-
role: 'CTO, Kwikku Interactive',
22-
serviceName: 'Server Setup & Hardening',
23-
rating: 5,
24-
},
25-
{
26-
quote: 'Our website and mail setup was done in a matter of hours. Saved us a lot of time and money.',
27-
author: 'Jason Lim',
28-
role: 'Business Owner',
29-
serviceName: 'Website Project Setup (Custom or CMS)',
30-
rating: 5,
31-
},
32-
{
33-
quote: 'My homelab is messed before. After consulting with Jeff, it is now stable, monitored, and easy to maintain. Thanks a lot!',
34-
author: 'K. Tan',
35-
role: 'Indie Dev',
36-
serviceName: 'Self‑Hosting & Homelab Consultation',
37-
rating: 5,
38-
},
39-
{
40-
quote: 'Jeff helped me set up my website and mail server in a matter of hours. Even though He is my cousin, I still want to give him a big thank you.',
41-
author: 'N. Chen',
42-
role: 'Individual',
43-
serviceName: 'Website Project Setup (Custom or CMS)',
44-
rating: 5,
45-
},
46-
];
9+
const servicesData = data.services;
10+
const testimonials = data.testimonials;
4711
4812
const jsonLd = {
4913
'@context': 'https://schema.org',
@@ -92,65 +56,17 @@ const jsonLd = {
9256
</div>
9357

9458
<div class="max-w-3xl mx-auto grid gap-4 sm:grid-cols-2">
95-
<section class="border border-muted rounded-lg p-4 flex flex-col gap-2">
96-
<h2 class="font-semibold text-xl text-[var(--color-primary)]">Server Setup & Hardening</h2>
97-
<p class="text-sm text-base04">Provision secure Linux servers with best practices and backups.</p>
98-
<ul class="list-disc list-inside text-sm">
99-
<li>Firewall, TLS, SSH and users</li>
100-
<li>Backups & recovery drills</li>
101-
<li>Baseline hardening</li>
102-
</ul>
103-
</section>
104-
105-
<section class="border border-muted rounded-lg p-4 flex flex-col gap-2">
106-
<h2 class="font-semibold text-xl text-[var(--color-primary)]">CI/CD Implementation</h2>
107-
<p class="text-sm text-base04">Build, test, and deploy reliably with modern pipelines.</p>
108-
<ul class="list-disc list-inside text-sm">
109-
<li>GitHub Actions / GitLab CI</li>
110-
<li>Multi‑env deployments</li>
111-
<li>Release workflows</li>
112-
</ul>
113-
</section>
114-
115-
<section class="border border-muted rounded-lg p-4 flex flex-col gap-2">
116-
<h2 class="font-semibold text-xl text-[var(--color-primary)]">Automation with Ansible</h2>
117-
<p class="text-sm text-base04">Idempotent provisioning and repeatable operations at any scale.</p>
118-
<ul class="list-disc list-inside text-sm">
119-
<li>Playbooks & roles</li>
120-
<li>Inventories & secrets</li>
121-
<li>Server fleet automation</li>
122-
</ul>
123-
</section>
124-
125-
<section class="border border-muted rounded-lg p-4 flex flex-col gap-2">
126-
<h2 class="font-semibold text-xl text-[var(--color-primary)]">Self‑Hosting & Homelab Consultation</h2>
127-
<p class="text-sm text-base04">Plan and operate personal services safely and sustainably.</p>
128-
<ul class="list-disc list-inside text-sm">
129-
<li>Reverse proxy & TLS</li>
130-
<li>Single‑sign on (SSO)</li>
131-
<li>Backups & monitoring guidance</li>
132-
</ul>
133-
</section>
134-
135-
<section class="border border-muted rounded-lg p-4 flex flex-col gap-2">
136-
<h2 class="font-semibold text-xl text-[var(--color-primary)]">Website Project Setup (Custom or CMS)</h2>
137-
<p class="text-sm text-base04">Kickstart your site with a custom build or a robust CMS.</p>
138-
<ul class="list-disc list-inside text-sm">
139-
<li>Astro / Next.js</li>
140-
<li>WordPress / Ghost</li>
141-
<li>Content & SEO basics</li>
142-
</ul>
143-
</section>
144-
145-
<section class="border border-muted rounded-lg p-4 flex flex-col gap-2">
146-
<h2 class="font-semibold text-xl text-[var(--color-primary)]">Monitoring Setup (Grafana & Prometheus)</h2>
147-
<p class="text-sm text-base04">Dashboards, alerts, and metrics that help you act quickly.</p>
148-
<ul class="list-disc list-inside text-sm">
149-
<li>Grafana dashboards & panels</li>
150-
<li>Prometheus scraping & exporters</li>
151-
<li>Alertmanager routing & notifications</li>
152-
</ul>
153-
</section>
59+
{servicesData.map((svc) => (
60+
<section class="border border-muted rounded-lg p-4 flex flex-col gap-2">
61+
<h2 class="font-semibold text-xl text-[var(--color-primary)]">{svc.name}</h2>
62+
<p class="text-sm text-base04">{svc.description}</p>
63+
{svc.features && svc.features.length ? (
64+
<ul class="list-disc list-inside text-sm">
65+
{svc.features.map((f) => (<li>{f}</li>))}
66+
</ul>
67+
) : null}
68+
</section>
69+
))}
15470
</div>
15571

15672
<div id="testimonials" class="max-w-3xl mx-auto mt-8" role="region" aria-label="Client testimonials">

src/types/services.ts

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
export interface ServiceItem {
2+
name: string;
3+
description: string;
4+
features?: string[]; // bullet points shown in the card
5+
category?: string; // optional canonical category
6+
}
7+
8+
export interface TestimonialItem {
9+
quote: string;
10+
author: string;
11+
role?: string;
12+
serviceName: string; // should reference ServiceItem.name
13+
rating: 1 | 2 | 3 | 4 | 5;
14+
}
15+
16+
export interface ServicesData {
17+
services: ServiceItem[];
18+
testimonials: TestimonialItem[];
19+
}

0 commit comments

Comments
 (0)