waitsec 0.4.5 → 0.5.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.cursor-plugin/plugin.json +1 -1
- package/README.md +18 -12
- package/bin/cli.mjs +15 -10
- package/package.json +1 -1
- package/plugin.json +1 -1
- package/skills/{waitsec-core → waitsec}/SKILL.md +20 -18
- package/skills/{waitsec-core → waitsec/references}/anti-overengineering.md +27 -15
- package/skills/waitsec/references/ask-first.md +112 -0
- package/skills/waitsec/references/debug-first.md +66 -0
- package/skills/waitsec/references/small-diff.md +63 -0
- package/skills/waitsec/references/verify-first.md +79 -0
- package/skills/waitsec/references/write-info-analyzer.md +117 -0
- package/skills/waitsec-code/SKILL.md +87 -12
- package/skills/waitsec-pagemaker/SKILL.md +622 -0
- package/skills/waitsec-pagemaker/references/about-me.md +161 -0
- package/skills/waitsec-pagemaker/references/article-single.md +168 -0
- package/skills/waitsec-pagemaker/references/blog-index.md +167 -0
- package/skills/waitsec-pagemaker/references/contact-page.md +162 -0
- package/skills/waitsec-pagemaker/references/landing-page.md +220 -0
- package/skills/waitsec-quality/SKILL.md +93 -14
- package/skills/waitsec-ui/SKILL.md +74 -16
- package/skills/waitsec-core/ask-first.md +0 -67
- package/skills/waitsec-core/debug-first.md +0 -54
- package/skills/waitsec-core/small-diff.md +0 -51
- package/skills/waitsec-core/verify-first.md +0 -67
|
@@ -0,0 +1,161 @@
|
|
|
1
|
+
# About Me & Portfolio Blueprint (waitsec-pagemaker)
|
|
2
|
+
|
|
3
|
+
Use this guide when creating a personal developer portfolio, founder bio, or engineer profile page. It ensures the page highlights real-world work and technical competence without cheesy resume clichés.
|
|
4
|
+
|
|
5
|
+
---
|
|
6
|
+
|
|
7
|
+
## Complete Page Anatomy & Responsive Flow
|
|
8
|
+
|
|
9
|
+
### 1. Intro Snapshot (The Header)
|
|
10
|
+
* **Desktop (1024px+):** Side-by-side layout. Profile photo or avatar on the left (80px to 96px), short 2-sentence bio on the right, followed by status badge (e.g. "Available for projects") and direct social links (GitHub, X, LinkedIn, Email).
|
|
11
|
+
* **Mobile (<768px):** Stacks vertically. Avatar centered or left-aligned with clean text underneath. Keep intro under 50 words so visitors see projects without scrolling endlessly.
|
|
12
|
+
|
|
13
|
+
### 2. Selected Projects Showcase
|
|
14
|
+
* **Desktop:** 2-column grid (`md:grid-cols-2 gap-6`). Each card highlights 1 tangible problem solved, tech stack badges, live demo link, and GitHub repository link.
|
|
15
|
+
* **Mobile:** 1-column vertical stack (`grid-cols-1 gap-6`). Full-width cards with large touch targets for external links.
|
|
16
|
+
|
|
17
|
+
### 3. Career & Experience Timeline
|
|
18
|
+
* **Desktop & Mobile:** Single vertical line aligned to the left edge with bullet dots. Never use an alternating left-and-right zigzag timeline that breaks on mobile.
|
|
19
|
+
* Content per role: Company name, job title, start/end dates, and 2 concise bullet points detailing measurable engineering impact.
|
|
20
|
+
|
|
21
|
+
### 4. Technical Skills & Tools
|
|
22
|
+
* **Desktop & Mobile:** Simple, clean text pills organized by category (Languages, Frameworks, Cloud & Databases, Tooling).
|
|
23
|
+
* Absolutely zero animated percentage bars or fake skill ratings.
|
|
24
|
+
|
|
25
|
+
### 5. Direct Reachout Section
|
|
26
|
+
* A clean footer box with a prominent email link (`mailto:your@email.com`) and location timezone.
|
|
27
|
+
|
|
28
|
+
---
|
|
29
|
+
|
|
30
|
+
## Detailed Pitfalls & The 5-Point Rule
|
|
31
|
+
|
|
32
|
+
### 1. The Fake Skill Percentage Bars
|
|
33
|
+
|
|
34
|
+
* **The Bad Habit:** Adding animated progress bars that claim "JavaScript: 95%", "Docker: 80%", "Teamwork: 90%".
|
|
35
|
+
* **The Problem:** Percentage numbers on human skills mean literally nothing. What does 95% of JavaScript even mean? Does it mean you wrote the V8 engine?
|
|
36
|
+
* **Why It Fails:** Senior hiring managers and engineering leads instantly recognize skill bars as amateur filler. It damages technical credibility.
|
|
37
|
+
* **Clean Fix:** Group skills into clear categorical text badges, or list them alongside the real projects where you actually used them:
|
|
38
|
+
```html
|
|
39
|
+
<div class="space-y-4">
|
|
40
|
+
<h3 class="text-sm font-semibold uppercase tracking-wider text-neutral-500">Core Technologies</h3>
|
|
41
|
+
<div class="flex flex-wrap gap-2">
|
|
42
|
+
<span class="px-3 py-1 bg-neutral-100 dark:bg-neutral-800 text-neutral-700 dark:text-neutral-300 text-xs rounded-md">TypeScript</span>
|
|
43
|
+
<span class="px-3 py-1 bg-neutral-100 dark:bg-neutral-800 text-neutral-700 dark:text-neutral-300 text-xs rounded-md">Next.js</span>
|
|
44
|
+
<span class="px-3 py-1 bg-neutral-100 dark:bg-neutral-800 text-neutral-700 dark:text-neutral-300 text-xs rounded-md">PostgreSQL</span>
|
|
45
|
+
<span class="px-3 py-1 bg-neutral-100 dark:bg-neutral-800 text-neutral-700 dark:text-neutral-300 text-xs rounded-md">Tailwind CSS</span>
|
|
46
|
+
</div>
|
|
47
|
+
</div>
|
|
48
|
+
```
|
|
49
|
+
* **The Waitsec Way:** Prove skills through projects and code, not through invented percentages.
|
|
50
|
+
|
|
51
|
+
### 2. The Alternating Zigzag Timeline on Mobile
|
|
52
|
+
|
|
53
|
+
* **The Bad Habit:** Creating a timeline where odd years are on the left of a center line and even years are on the right.
|
|
54
|
+
* **The Problem:** On a 375px phone screen, dividing the screen in half leaves only 140px of width for text. Sentences wrap every 2 words.
|
|
55
|
+
* **Why It Fails:** It looks like a tangled mess on phones, and dates collide with company names.
|
|
56
|
+
* **Clean Fix:** Use a left-aligned timeline across all screen sizes. The timeline border sits strictly on the left margin:
|
|
57
|
+
```html
|
|
58
|
+
<div class="relative border-l border-neutral-200 dark:border-neutral-800 ml-3 space-y-8">
|
|
59
|
+
<div class="relative pl-6">
|
|
60
|
+
<!-- Timeline Node Dot -->
|
|
61
|
+
<div class="absolute -left-1.5 top-1.5 w-3 h-3 bg-neutral-900 dark:bg-white rounded-full"></div>
|
|
62
|
+
<div class="text-xs text-neutral-400 font-medium">2024 - Present</div>
|
|
63
|
+
<h3 class="text-base font-bold text-neutral-900 dark:text-white mt-1">Lead Backend Engineer • Fastro</h3>
|
|
64
|
+
<p class="text-sm text-neutral-600 dark:text-neutral-400 mt-2">
|
|
65
|
+
Redesigned API gateway architecture, reducing response latency by 35%.
|
|
66
|
+
</p>
|
|
67
|
+
</div>
|
|
68
|
+
</div>
|
|
69
|
+
```
|
|
70
|
+
* **The Waitsec Way:** Keep mobile layouts simple. A single vertical line reads naturally from top to bottom on any device.
|
|
71
|
+
|
|
72
|
+
### 3. Vague Project Cards With No Live Proof
|
|
73
|
+
|
|
74
|
+
* **The Bad Habit:** Listing 8 generic project cards with titles like "E-Commerce App" and "Task Manager", with no live demo and no source code link.
|
|
75
|
+
* **The Problem:** The visitor has no way to verify whether the project was actually built or just copied from a YouTube tutorial.
|
|
76
|
+
* **Why It Fails:** Recruiters and clients want to see live code and architecture decisions. Dead links cause visitors to bounce.
|
|
77
|
+
* **Clean Fix:** Showcase 3 or 4 high-quality projects. For each project, explain the technical problem it solved, provide a live link, and link the GitHub repository:
|
|
78
|
+
```html
|
|
79
|
+
<div class="p-6 border border-neutral-200 dark:border-neutral-800 rounded-xl hover:border-neutral-400 transition-colors">
|
|
80
|
+
<div class="flex items-center justify-between">
|
|
81
|
+
<h3 class="text-lg font-bold text-neutral-900 dark:text-white">Waitsec CLI</h3>
|
|
82
|
+
<div class="flex items-center gap-3 text-sm">
|
|
83
|
+
<a href="https://github.com/..." class="text-neutral-500 hover:text-neutral-900">GitHub →</a>
|
|
84
|
+
<a href="https://waitsec.dev" class="text-neutral-900 dark:text-white font-medium">Live →</a>
|
|
85
|
+
</div>
|
|
86
|
+
</div>
|
|
87
|
+
<p class="text-sm text-neutral-600 dark:text-neutral-400 mt-2">
|
|
88
|
+
Lightweight engineering discipline tool for AI coding agents with zero external dependencies.
|
|
89
|
+
</p>
|
|
90
|
+
<div class="flex gap-2 mt-4 text-xs font-mono text-neutral-500">
|
|
91
|
+
<span>Node.js</span> • <span>ESM</span> • <span>CLI</span>
|
|
92
|
+
</div>
|
|
93
|
+
</div>
|
|
94
|
+
```
|
|
95
|
+
* **The Waitsec Way:** Fewer projects with real code beats twenty shallow placeholders.
|
|
96
|
+
|
|
97
|
+
### 4. Hiding the Contact Email Behind a Wall
|
|
98
|
+
|
|
99
|
+
* **The Bad Habit:** Hiding the contact option behind a broken third-party contact form with 8 mandatory fields.
|
|
100
|
+
* **The Problem:** The user just wants to send a quick freelance inquiry or collaboration email, but the form errors out or sends into a void.
|
|
101
|
+
* **Why It Fails:** Friction kills inbound opportunities. If people cannot easily email you, they will message someone else.
|
|
102
|
+
* **Clean Fix:** Always provide a direct, visible email address with a clickable `mailto:` link:
|
|
103
|
+
```html
|
|
104
|
+
<div class="p-8 bg-neutral-50 dark:bg-neutral-900 rounded-2xl border border-neutral-200 dark:border-neutral-800 text-center">
|
|
105
|
+
<h2 class="text-2xl font-bold">Let's build something together</h2>
|
|
106
|
+
<p class="text-neutral-600 dark:text-neutral-400 mt-2 text-sm">Currently open to select contract and advisory roles.</p>
|
|
107
|
+
<a href="mailto:hello@example.com" class="inline-block mt-4 px-6 py-3 bg-neutral-900 text-white dark:bg-white dark:text-neutral-900 font-medium rounded-lg">
|
|
108
|
+
hello@example.com
|
|
109
|
+
</a>
|
|
110
|
+
</div>
|
|
111
|
+
```
|
|
112
|
+
* **The Waitsec Way:** Remove barriers between you and your audience. Make reaching out as easy as clicking one button.
|
|
113
|
+
|
|
114
|
+
---
|
|
115
|
+
|
|
116
|
+
## SEO, GEO & Structured Data (About & Portfolio)
|
|
117
|
+
|
|
118
|
+
- Title: full name plus role, for example "Ilyas Mukhlisin, Backend Engineer", about 50 to 60 characters.
|
|
119
|
+
- Meta description: who you are, what you build, and how to reach you, about 140 to 160 characters.
|
|
120
|
+
- One `<h1>` with your name.
|
|
121
|
+
- Server-render the bio, project list, and contact email.
|
|
122
|
+
- Add `sameAs` links to GitHub, LinkedIn, and X so engines can confirm the identity.
|
|
123
|
+
- Describe each project with a concrete outcome, not a vague claim, so answer engines have something to quote.
|
|
124
|
+
|
|
125
|
+
### JSON-LD for an About or Portfolio Page
|
|
126
|
+
|
|
127
|
+
```html
|
|
128
|
+
<script type="application/ld+json">
|
|
129
|
+
{
|
|
130
|
+
"@context": "https://schema.org",
|
|
131
|
+
"@type": "ProfilePage",
|
|
132
|
+
"url": "https://example.com/about",
|
|
133
|
+
"mainEntity": {
|
|
134
|
+
"@type": "Person",
|
|
135
|
+
"name": "Your Name",
|
|
136
|
+
"jobTitle": "Backend Engineer",
|
|
137
|
+
"url": "https://example.com",
|
|
138
|
+
"image": "https://example.com/images/avatar.jpg",
|
|
139
|
+
"worksFor": { "@type": "Organization", "name": "Fastro" },
|
|
140
|
+
"knowsAbout": ["Laravel", "PostgreSQL", "API design"],
|
|
141
|
+
"sameAs": [
|
|
142
|
+
"https://github.com/username",
|
|
143
|
+
"https://www.linkedin.com/in/username"
|
|
144
|
+
]
|
|
145
|
+
}
|
|
146
|
+
}
|
|
147
|
+
</script>
|
|
148
|
+
```
|
|
149
|
+
|
|
150
|
+
When the about page is part of a company site, add an `Organization` node and connect it with `worksFor` or `memberOf`.
|
|
151
|
+
|
|
152
|
+
---
|
|
153
|
+
|
|
154
|
+
## Pre-Flight Checklist for About Me & Portfolio Pages
|
|
155
|
+
|
|
156
|
+
- [ ] Are all fake animated skill percentage bars removed in favor of clean categorical tags?
|
|
157
|
+
- [ ] Is the career timeline strictly left-aligned with zero alternating zigzag layouts?
|
|
158
|
+
- [ ] Does every featured project have a working live link or public repository link?
|
|
159
|
+
- [ ] Is there a direct, clickable `mailto:` link clearly visible on the page?
|
|
160
|
+
- [ ] Do project cards collapse into a clean single vertical stack on mobile screens?
|
|
161
|
+
- [ ] Is there a valid ProfilePage with Person data, including sameAs links to real profiles?
|
|
@@ -0,0 +1,168 @@
|
|
|
1
|
+
# Single Article & Reading View Blueprint (waitsec-pagemaker)
|
|
2
|
+
|
|
3
|
+
Use this guide when creating a single article view, blog post template, or markdown documentation page. It ensures readers can focus comfortably on long-form text without eye strain on any device.
|
|
4
|
+
|
|
5
|
+
---
|
|
6
|
+
|
|
7
|
+
## Complete Page Anatomy & Responsive Flow
|
|
8
|
+
|
|
9
|
+
### 1. Top Navigation & Context
|
|
10
|
+
* **Desktop & Mobile:** A clean back link at the top (for example: "← Back to all articles"). Keeps the reader oriented so they never feel lost in deep content.
|
|
11
|
+
|
|
12
|
+
### 2. Article Header & Metadata
|
|
13
|
+
* **Category Badge:** Small tag indicating the topic (e.g. "Tutorial" or "Architecture").
|
|
14
|
+
* **Main Title (`<h1>`):** Bold, clear, and prominent. Use `text-3xl sm:text-4xl lg:text-5xl font-bold tracking-tight`.
|
|
15
|
+
* **Author & Meta Row:** Author avatar, full name, publication date, and estimated reading time (e.g. "Sep 12, 2026 • 6 min read").
|
|
16
|
+
|
|
17
|
+
### 3. Reading Container & Measure
|
|
18
|
+
* **Desktop (1024px+):** Constrain the reading container to `max-w-prose` or `max-w-3xl mx-auto px-4`. Never allow lines of text to stretch wider than 70 to 75 characters per line.
|
|
19
|
+
* **Mobile (<768px):** Full width with generous side padding (`px-4 sm:px-6`). Use comfortable 16px or 17px body text with relaxed line-height.
|
|
20
|
+
|
|
21
|
+
### 4. Rich Media & Code Elements
|
|
22
|
+
* **Code Blocks:** Dark background, syntax highlighting, monospace font, with an explicit `overflow-x-auto` wrapper so long lines of code scroll horizontally instead of blowing up the mobile page.
|
|
23
|
+
* **Blockquotes:** Indented with a 3px solid neutral accent border on the left and slightly italicized text.
|
|
24
|
+
* **Tables:** Always wrapped in a container with `overflow-x-auto` to allow smooth horizontal scrolling on phones.
|
|
25
|
+
|
|
26
|
+
### 5. Article Footer & Engagement
|
|
27
|
+
* **Author Card:** 2-sentence bio with direct links to GitHub or social profiles.
|
|
28
|
+
* **Next / Previous Navigation:** 2-column cards at the bottom of the article linking to the next piece of content.
|
|
29
|
+
|
|
30
|
+
---
|
|
31
|
+
|
|
32
|
+
## Detailed Pitfalls & The 5-Point Rule
|
|
33
|
+
|
|
34
|
+
### 1. The 1920px Full-Width Reading Nightmare
|
|
35
|
+
|
|
36
|
+
* **The Bad Habit:** Letting article paragraphs stretch 100% across the full width of an ultrawide desktop monitor.
|
|
37
|
+
* **The Problem:** Lines of text become 180 characters long. Readers have to physically turn their heads from left to right to finish a single sentence.
|
|
38
|
+
* **Why It Fails:** Human eyes lose track of the next line when scanning sentences longer than 75 characters. Readers get disoriented, skip paragraphs, and leave out of fatigue.
|
|
39
|
+
* **Clean Fix:** Strictly constrain the text wrapper using `max-w-3xl` or `max-w-prose` with centered margins:
|
|
40
|
+
```html
|
|
41
|
+
<main class="w-full max-w-3xl mx-auto px-4 sm:px-6 py-12">
|
|
42
|
+
<article class="prose prose-neutral dark:prose-invert max-w-none">
|
|
43
|
+
<p class="text-base sm:text-lg leading-relaxed text-neutral-800">
|
|
44
|
+
Paragraph text stays comfortable and readable across any screen size.
|
|
45
|
+
</p>
|
|
46
|
+
</article>
|
|
47
|
+
</main>
|
|
48
|
+
```
|
|
49
|
+
* **The Waitsec Way:** Reading comfort is non-negotiable. Cap line length between 60 and 75 characters per line on all devices.
|
|
50
|
+
|
|
51
|
+
### 2. Code Blocks That Break Mobile Viewports
|
|
52
|
+
|
|
53
|
+
* **The Bad Habit:** Rendering `<pre><code>` blocks with default styling or `white-space: pre` without horizontal overflow protection.
|
|
54
|
+
* **The Problem:** A single long line of code (like a long URL or terminal command) forces the entire mobile page to expand to 900px width.
|
|
55
|
+
* **Why It Fails:** The entire website starts wobbling sideways on mobile phones. Users have to pinch-to-zoom just to recenter the text.
|
|
56
|
+
* **Clean Fix:** Always wrap code blocks with `overflow-x-auto` and specify a clean monospace font stack:
|
|
57
|
+
```html
|
|
58
|
+
<div class="my-6 rounded-xl bg-neutral-900 text-neutral-100 p-4 overflow-x-auto border border-neutral-800">
|
|
59
|
+
<pre class="font-mono text-sm leading-normal"><code>const response = await fetch("https://api.example.com/v1/data/endpoint/users");</code></pre>
|
|
60
|
+
</div>
|
|
61
|
+
```
|
|
62
|
+
* **The Waitsec Way:** Code snippets must adapt to the screen, not break the screen. Contain horizontal overflow strictly inside the code block.
|
|
63
|
+
|
|
64
|
+
### 3. Markdown Tables Clipping Columns on Phones
|
|
65
|
+
|
|
66
|
+
* **The Bad Habit:** Inserting a 5-column data table inside an article and expecting it to fit on a 375px phone screen.
|
|
67
|
+
* **The Problem:** The rightmost 3 columns get permanently cut off, or the text inside table cells squishes into unreadable single-letter stacks.
|
|
68
|
+
* **Why It Fails:** Tables cannot shrink below the width of their text. When table boundaries are locked, readers miss crucial data.
|
|
69
|
+
* **Clean Fix:** Wrap every markdown table in an explicit scroll container with a visual scroll indicator:
|
|
70
|
+
```html
|
|
71
|
+
<div class="my-6 w-full overflow-x-auto border border-neutral-200 rounded-lg">
|
|
72
|
+
<table class="w-full min-w-[500px] text-left text-sm">
|
|
73
|
+
<thead class="bg-neutral-50 border-b border-neutral-200">...</thead>
|
|
74
|
+
<tbody class="divide-y divide-neutral-200">...</tbody>
|
|
75
|
+
</table>
|
|
76
|
+
</div>
|
|
77
|
+
```
|
|
78
|
+
* **The Waitsec Way:** Tables are inherently wide. Always give them dedicated horizontal scroll containers so the main page stays rock solid.
|
|
79
|
+
|
|
80
|
+
### 4. Header Crowding & Suffocating Line-Height
|
|
81
|
+
|
|
82
|
+
* **The Bad Habit:** Using tight line-height (`leading-tight`) on body paragraphs and putting zero top margin above `<h2>` and `<h3>` subheadings.
|
|
83
|
+
* **The Problem:** Subheadings look glued to the paragraph above them, and dense blocks of text look like intimidating walls of gray ink.
|
|
84
|
+
* **Why It Fails:** Reading on a screen is tiring. Without generous breathing room, readers skim and bounce.
|
|
85
|
+
* **Clean Fix:** Give subheadings double the margin above them (`mt-10 mb-4`), and use relaxed line height (`leading-relaxed` or `line-height: 1.75`) for body text:
|
|
86
|
+
```html
|
|
87
|
+
<h2 class="text-2xl font-bold tracking-tight text-neutral-900 mt-12 mb-4">
|
|
88
|
+
Core Architectural Changes
|
|
89
|
+
</h2>
|
|
90
|
+
<p class="text-base sm:text-lg leading-relaxed text-neutral-700 mb-6">
|
|
91
|
+
Notice how the generous space above makes it instantly obvious that a new topic has begun.
|
|
92
|
+
</p>
|
|
93
|
+
```
|
|
94
|
+
* **The Waitsec Way:** Visual breathing room creates typographic rhythm. Generous spacing makes complex technical content easy to absorb.
|
|
95
|
+
|
|
96
|
+
---
|
|
97
|
+
|
|
98
|
+
## SEO, GEO & Structured Data (Article Page)
|
|
99
|
+
|
|
100
|
+
- Title: the article headline, optionally with the site name, about 50 to 60 characters.
|
|
101
|
+
- Meta description: an honest summary of the article, about 140 to 160 characters.
|
|
102
|
+
- One `<h1>` that matches the headline.
|
|
103
|
+
- State the article's main answer in the first paragraph, before background detail.
|
|
104
|
+
- Use question-shaped `<h2>` and `<h3>` headings, each followed by a direct answer.
|
|
105
|
+
- Show `datePublished` and `dateModified` visibly near the top, and keep both in the schema.
|
|
106
|
+
- Give the cover image descriptive alt text and an absolute URL.
|
|
107
|
+
- Keep the article body server-rendered.
|
|
108
|
+
|
|
109
|
+
### JSON-LD for an Article Page
|
|
110
|
+
|
|
111
|
+
The `Article` type is safe, while `BlogPosting` is more specific for blog posts. Use the one that matches the page. Add `BreadcrumbList` so search engines can show the path.
|
|
112
|
+
|
|
113
|
+
```html
|
|
114
|
+
<script type="application/ld+json">
|
|
115
|
+
{
|
|
116
|
+
"@context": "https://schema.org",
|
|
117
|
+
"@graph": [
|
|
118
|
+
{
|
|
119
|
+
"@type": "BlogPosting",
|
|
120
|
+
"headline": "Why Errors Appear as Codes and How to Read Them",
|
|
121
|
+
"description": "A short, honest summary of what the article explains.",
|
|
122
|
+
"image": "https://example.com/storage/blog-thumbnails/cover.webp",
|
|
123
|
+
"datePublished": "2026-09-04T09:56:00+07:00",
|
|
124
|
+
"dateModified": "2026-09-04T09:56:00+07:00",
|
|
125
|
+
"author": {
|
|
126
|
+
"@type": "Person",
|
|
127
|
+
"name": "Ilyas Mukhlisin",
|
|
128
|
+
"url": "https://example.com/about"
|
|
129
|
+
},
|
|
130
|
+
"publisher": {
|
|
131
|
+
"@type": "Organization",
|
|
132
|
+
"name": "Fikselink",
|
|
133
|
+
"logo": {
|
|
134
|
+
"@type": "ImageObject",
|
|
135
|
+
"url": "https://example.com/images/logo.png"
|
|
136
|
+
}
|
|
137
|
+
},
|
|
138
|
+
"mainEntityOfPage": {
|
|
139
|
+
"@type": "WebPage",
|
|
140
|
+
"@id": "https://example.com/blog/post/why-errors-appear-as-codes"
|
|
141
|
+
},
|
|
142
|
+
"articleSection": "Technology",
|
|
143
|
+
"keywords": "error code, HTTP status code, how to read errors"
|
|
144
|
+
},
|
|
145
|
+
{
|
|
146
|
+
"@type": "BreadcrumbList",
|
|
147
|
+
"itemListElement": [
|
|
148
|
+
{ "@type": "ListItem", "position": 1, "name": "Home", "item": "https://example.com" },
|
|
149
|
+
{ "@type": "ListItem", "position": 2, "name": "Blog", "item": "https://example.com/blog" },
|
|
150
|
+
{ "@type": "ListItem", "position": 3, "name": "Why Errors Appear as Codes", "item": "https://example.com/blog/post/why-errors-appear-as-codes" }
|
|
151
|
+
]
|
|
152
|
+
}
|
|
153
|
+
]
|
|
154
|
+
}
|
|
155
|
+
</script>
|
|
156
|
+
```
|
|
157
|
+
|
|
158
|
+
---
|
|
159
|
+
|
|
160
|
+
## Pre-Flight Checklist for Single Article Pages
|
|
161
|
+
|
|
162
|
+
- [ ] Is the article reading width capped at `max-w-3xl` or `65-75ch` to prevent eye strain?
|
|
163
|
+
- [ ] Do all code blocks and tables have `overflow-x-auto` to prevent mobile viewport wobbling?
|
|
164
|
+
- [ ] Is body paragraph line-height set to relaxed (`leading-relaxed` / 1.75)?
|
|
165
|
+
- [ ] Are subheadings given generous top margin (`mt-10` to `mt-12`) to separate topics clearly?
|
|
166
|
+
- [ ] Is there a clear back-navigation link at the top of the article?
|
|
167
|
+
- [ ] Does the first paragraph answer the main question directly?
|
|
168
|
+
- [ ] Is there a valid BlogPosting or Article block with author, publisher, and ISO 8601 dates?
|
|
@@ -0,0 +1,167 @@
|
|
|
1
|
+
# Blog & Article Index Blueprint (waitsec-pagemaker)
|
|
2
|
+
|
|
3
|
+
Use this guide when creating a blog listing, article archive, or news feed. It ensures your readers can easily discover, browse, and filter articles across phones, tablets, and wide monitors.
|
|
4
|
+
|
|
5
|
+
---
|
|
6
|
+
|
|
7
|
+
## Complete Page Anatomy & Responsive Flow
|
|
8
|
+
|
|
9
|
+
### 1. Header & Category Bar
|
|
10
|
+
* **Desktop (1024px+):** Clean page heading (e.g. "Engineering Journal"), a 1-sentence descriptor, and a horizontal row of category pills (All, Architecture, Security, Tutorials).
|
|
11
|
+
* **Mobile (<768px):** Category pills sit in a smooth horizontally scrollable row (`overflow-x-auto no-scrollbar`) with 44px touch targets. Never wrap 15 category tags into four messy vertical lines.
|
|
12
|
+
|
|
13
|
+
### 2. Featured / Latest Story (Hero Card)
|
|
14
|
+
* **Desktop:** Wide horizontal card (spans 2 columns or full width). High-resolution cover image on the left (50% width), title, category tag, 3-line excerpt, and author metadata on the right (50% width).
|
|
15
|
+
* **Mobile:** Stacks vertically. Image on top (aspect-video), followed by title, date, reading time, and excerpt.
|
|
16
|
+
|
|
17
|
+
### 3. Article Stream / Card Grid
|
|
18
|
+
* **Desktop Grid Option:** 3-column card grid (`lg:grid-cols-3 gap-8`).
|
|
19
|
+
* **Desktop Feed Option (Substack/Medium Style):** Single centered feed (`max-w-3xl mx-auto space-y-8`). Highly recommended for tech blogs.
|
|
20
|
+
* **Tablet:** 2-column grid (`md:grid-cols-2 gap-6`).
|
|
21
|
+
* **Mobile:** 1-column vertical stack (`grid-cols-1 gap-6`). Every card gets full screen width with generous tap target padding.
|
|
22
|
+
|
|
23
|
+
### 4. Article Card Anatomy
|
|
24
|
+
Every article preview card must contain:
|
|
25
|
+
1. Category badge (e.g. "Security" or "CSS").
|
|
26
|
+
2. Article title (`<h2>` or `<h3>`) with clear hover underline or color shift.
|
|
27
|
+
3. Reading metadata: Publication date and estimated reading time (e.g. "Sep 12, 2026 • 5 min read").
|
|
28
|
+
4. Short excerpt: strictly truncated to 2 or 3 lines (`line-clamp-2` or `line-clamp-3`).
|
|
29
|
+
5. Author snapshot: small 28px avatar and author name.
|
|
30
|
+
|
|
31
|
+
### 5. Pagination & Page Navigation
|
|
32
|
+
* **Desktop & Mobile:** Explicit page numbers or simple "Previous Page" and "Next Page" buttons.
|
|
33
|
+
* Avoid infinite scroll by default so users can reach the footer and search filters comfortably.
|
|
34
|
+
|
|
35
|
+
---
|
|
36
|
+
|
|
37
|
+
## Detailed Pitfalls & The 5-Point Rule
|
|
38
|
+
|
|
39
|
+
### 1. The Giant Image Trap on Mobile
|
|
40
|
+
|
|
41
|
+
* **The Bad Habit:** Placing massive 16:9 cover images with fixed 400px heights above every single article card.
|
|
42
|
+
* **The Problem:** On a phone, one single article card fills the entire screen. The user has to scroll 3 full times just to see two article titles.
|
|
43
|
+
* **Why It Fails:** People browse blog indexes to scan headlines quickly. Giant thumbnail images waste mobile vertical space and burn unnecessary cellular data.
|
|
44
|
+
* **Clean Fix:** Use compact thumbnail aspect ratios on mobile, or switch to a clean text-first layout where thumbnails are small squares placed on the right side:
|
|
45
|
+
```html
|
|
46
|
+
<article class="flex flex-col sm:flex-row items-start justify-between gap-4 py-6 border-b border-neutral-200">
|
|
47
|
+
<div class="flex-1">
|
|
48
|
+
<span class="text-xs font-semibold text-neutral-500 uppercase">Architecture</span>
|
|
49
|
+
<h2 class="text-xl font-bold mt-1 hover:text-neutral-600">
|
|
50
|
+
<a href="/blog/scaling-sqlite">How We Scaled SQLite to 100k Requests</a>
|
|
51
|
+
</h2>
|
|
52
|
+
<p class="text-sm text-neutral-600 mt-2 line-clamp-2">
|
|
53
|
+
A practical walkthrough of write-ahead logging and connection pooling.
|
|
54
|
+
</p>
|
|
55
|
+
<div class="text-xs text-neutral-400 mt-3">Sep 12, 2026 • 4 min read</div>
|
|
56
|
+
</div>
|
|
57
|
+
<!-- Small thumbnail on right (tablet/desktop), hidden or compact on mobile -->
|
|
58
|
+
<div class="w-full sm:w-32 h-32 bg-neutral-100 rounded-lg overflow-hidden shrink-0">...</div>
|
|
59
|
+
</article>
|
|
60
|
+
```
|
|
61
|
+
* **The Waitsec Way:** A blog index is an index for reading. Headlines and excerpts must always take priority over decorative stock images.
|
|
62
|
+
|
|
63
|
+
### 2. The Wrapping Category Pill Explosion
|
|
64
|
+
|
|
65
|
+
* **The Bad Habit:** Displaying 10 or 15 topic tags ("JavaScript", "Python", "Database", "Design", "DevOps") as inline flex pills that wrap into 4 uneven rows on mobile.
|
|
66
|
+
* **The Problem:** The top third of the phone screen is consumed by a wall of colorful tag pills, pushing the actual articles out of view.
|
|
67
|
+
* **Why It Fails:** It looks messy, creates visual clutter, and forces mobile users to scroll before they even see an article.
|
|
68
|
+
* **Clean Fix:** Use a single horizontal scrolling row on mobile, or use a clean dropdown selector:
|
|
69
|
+
```html
|
|
70
|
+
<div class="flex items-center gap-2 overflow-x-auto pb-2 -mx-4 px-4 sm:mx-0 sm:px-0 scrollbar-none">
|
|
71
|
+
<button class="px-4 py-2 text-xs font-semibold bg-neutral-900 text-white rounded-full shrink-0">All Posts</button>
|
|
72
|
+
<button class="px-4 py-2 text-xs font-semibold bg-neutral-100 text-neutral-700 rounded-full shrink-0 hover:bg-neutral-200">Security</button>
|
|
73
|
+
<button class="px-4 py-2 text-xs font-semibold bg-neutral-100 text-neutral-700 rounded-full shrink-0 hover:bg-neutral-200">Architecture</button>
|
|
74
|
+
<button class="px-4 py-2 text-xs font-semibold bg-neutral-100 text-neutral-700 rounded-full shrink-0 hover:bg-neutral-200">Frontend</button>
|
|
75
|
+
</div>
|
|
76
|
+
```
|
|
77
|
+
* **The Waitsec Way:** Protect vertical mobile screen space. Keep navigation filters on a single horizontal plane.
|
|
78
|
+
|
|
79
|
+
### 3. The Uncontrollable Infinite Scroll
|
|
80
|
+
|
|
81
|
+
* **The Bad Habit:** Loading 20 more articles automatically every time the user scrolls near the bottom of the page, with zero option to stop.
|
|
82
|
+
* **The Problem:** The footer, contact links, copyright, and RSS feed links become completely unreachable because the page keeps jumping and inserting new items.
|
|
83
|
+
* **Why It Fails:** Users get trapped in an endless scroll. If they want to find an older article or visit the privacy policy, they are blocked.
|
|
84
|
+
* **Clean Fix:** Use clean, explicit pagination buttons or a manual "Load More Articles" button that only triggers when clicked:
|
|
85
|
+
```html
|
|
86
|
+
<div class="flex items-center justify-between pt-10 border-t border-neutral-200">
|
|
87
|
+
<a href="?page=1" class="px-4 py-2 text-sm font-medium border border-neutral-300 rounded-lg hover:bg-neutral-50">
|
|
88
|
+
← Newer Posts
|
|
89
|
+
</a>
|
|
90
|
+
<span class="text-xs text-neutral-500">Page 2 of 8</span>
|
|
91
|
+
<a href="?page=3" class="px-4 py-2 text-sm font-medium border border-neutral-300 rounded-lg hover:bg-neutral-50">
|
|
92
|
+
Older Posts →
|
|
93
|
+
</a>
|
|
94
|
+
</div>
|
|
95
|
+
```
|
|
96
|
+
* **The Waitsec Way:** Put the user in total control of their navigation. Never trap users with automatic background triggers.
|
|
97
|
+
|
|
98
|
+
### 4. The Tiny Unreadable Date Stamp
|
|
99
|
+
|
|
100
|
+
* **The Bad Habit:** Showing dates in 9px light gray text (`text-[9px] text-gray-300`), making it nearly invisible against white backgrounds.
|
|
101
|
+
* **The Problem:** Readers have no idea whether an engineering tutorial was written yesterday or seven years ago.
|
|
102
|
+
* **Why It Fails:** Outdated software tutorials waste hours of developer time. Freshness is one of the most critical decision factors for technical articles.
|
|
103
|
+
* **Clean Fix:** Display dates and reading times in clear, readable 12px or 13px neutral text with proper contrast:
|
|
104
|
+
```html
|
|
105
|
+
<div class="flex items-center gap-2 text-xs text-neutral-500 font-medium">
|
|
106
|
+
<time datetime="2026-09-12">Sep 12, 2026</time>
|
|
107
|
+
<span>•</span>
|
|
108
|
+
<span>4 min read</span>
|
|
109
|
+
</div>
|
|
110
|
+
```
|
|
111
|
+
* **The Waitsec Way:** Metadata gives context to content. Make publication dates and reading times clearly legible.
|
|
112
|
+
|
|
113
|
+
---
|
|
114
|
+
|
|
115
|
+
## SEO, GEO & Structured Data (Blog Index)
|
|
116
|
+
|
|
117
|
+
- Title: blog name plus its topic focus, about 50 to 60 characters.
|
|
118
|
+
- Meta description: what the blog covers and who it helps, about 140 to 160 characters.
|
|
119
|
+
- One `<h1>` for the index title, and `<h2>` for each article title.
|
|
120
|
+
- Server-render article titles, excerpts, and dates so crawlers read them without JavaScript.
|
|
121
|
+
- Link each card with the article title as anchor text, not "read more".
|
|
122
|
+
- Point a canonical tag at the canonical page of the listing, and keep paginated pages self-canonical.
|
|
123
|
+
- Keep the publish date and reading time visible, because freshness matters to both search and answer engines.
|
|
124
|
+
|
|
125
|
+
### JSON-LD for a Blog Index
|
|
126
|
+
|
|
127
|
+
```html
|
|
128
|
+
<script type="application/ld+json">
|
|
129
|
+
{
|
|
130
|
+
"@context": "https://schema.org",
|
|
131
|
+
"@type": "CollectionPage",
|
|
132
|
+
"name": "Engineering Journal",
|
|
133
|
+
"url": "https://example.com/blog",
|
|
134
|
+
"description": "Articles about software architecture, security, and frontend engineering.",
|
|
135
|
+
"isPartOf": { "@type": "WebSite", "url": "https://example.com" },
|
|
136
|
+
"mainEntity": {
|
|
137
|
+
"@type": "ItemList",
|
|
138
|
+
"itemListElement": [
|
|
139
|
+
{
|
|
140
|
+
"@type": "ListItem",
|
|
141
|
+
"position": 1,
|
|
142
|
+
"url": "https://example.com/blog/scaling-sqlite"
|
|
143
|
+
},
|
|
144
|
+
{
|
|
145
|
+
"@type": "ListItem",
|
|
146
|
+
"position": 2,
|
|
147
|
+
"url": "https://example.com/blog/reading-stack-traces"
|
|
148
|
+
}
|
|
149
|
+
]
|
|
150
|
+
}
|
|
151
|
+
}
|
|
152
|
+
</script>
|
|
153
|
+
```
|
|
154
|
+
|
|
155
|
+
Use `Blog` instead of `CollectionPage` when the listing is a true blog. Include one `ListItem` per visible article, in the same order shown on the page.
|
|
156
|
+
|
|
157
|
+
---
|
|
158
|
+
|
|
159
|
+
## Pre-Flight Checklist for Blog Index Pages
|
|
160
|
+
|
|
161
|
+
- [ ] Do article cards stack into a clean single column on mobile without horizontal scrolling?
|
|
162
|
+
- [ ] Are category filter pills contained in a single horizontal scrollable row on mobile?
|
|
163
|
+
- [ ] Are article excerpts clamped to 2 or 3 lines so cards maintain a predictable height?
|
|
164
|
+
- [ ] Can visitors comfortably reach the footer without being trapped by automatic infinite scroll?
|
|
165
|
+
- [ ] Are publication dates and reading estimates clearly legible with strong contrast?
|
|
166
|
+
- [ ] Does the page expose a valid CollectionPage or Blog ItemList schema?
|
|
167
|
+
- [ ] Do article cards use the article title as anchor text instead of "read more"?
|
|
@@ -0,0 +1,162 @@
|
|
|
1
|
+
# Contact Page Blueprint (waitsec-pagemaker)
|
|
2
|
+
|
|
3
|
+
Use this guide when creating a contact page, support inquiry form, or feedback screen. It ensures users can reach out smoothly on mobile and desktop without friction or broken form states.
|
|
4
|
+
|
|
5
|
+
---
|
|
6
|
+
|
|
7
|
+
## Complete Page Anatomy & Responsive Flow
|
|
8
|
+
|
|
9
|
+
### 1. Header & Clear Expectations
|
|
10
|
+
* **Desktop & Mobile:** Clear heading ("Get in Touch" or "Contact Us"), followed by an honest response estimate (e.g. "We typically respond within 24 business hours"). Setting expectations prevents users from sending repeat tickets.
|
|
11
|
+
|
|
12
|
+
### 2. Form Layout & Alternative Channels (The Split)
|
|
13
|
+
* **Desktop (1024px+):** 2-column layout (`grid grid-cols-1 lg:grid-cols-12 gap-12`).
|
|
14
|
+
- Left Side (7 cols): Clean form card with minimal inputs.
|
|
15
|
+
- Right Side (5 cols): Direct contact box with direct email, office address, timezone, and live status badge.
|
|
16
|
+
* **Mobile (<768px):** Single vertical stack. The form appears first at the top. The direct contact details and social links appear below the form.
|
|
17
|
+
|
|
18
|
+
### 3. Minimal Field Discipline
|
|
19
|
+
Strictly limit input fields to what is necessary:
|
|
20
|
+
1. Full Name (`<input type="text" required>`)
|
|
21
|
+
2. Email Address (`<input type="email" required>`)
|
|
22
|
+
3. Topic / Category (clean `<select>` dropdown or horizontal radio pills)
|
|
23
|
+
4. Message (`<textarea rows="4" required>`)
|
|
24
|
+
Never demand phone numbers, fax numbers, company size, or physical mailing address for a general contact form.
|
|
25
|
+
|
|
26
|
+
### 4. Interactive States (Feedback Loop)
|
|
27
|
+
* **Default State:** Clean borders with high contrast labels.
|
|
28
|
+
* **Typing / Focus State:** High-contrast focus ring around active input (`focus-visible:ring-2 focus-visible:ring-neutral-900`).
|
|
29
|
+
* **Submitting State:** The submit button disables immediately and shows a clean spinner with "Sending...".
|
|
30
|
+
* **Success State:** The form disappears and displays an inline confirmation message: "Thank you! We received your message and will reply soon."
|
|
31
|
+
* **Error State:** Specific field outlines turn red (`border-red-500`) with a clear error explanation directly below the field.
|
|
32
|
+
|
|
33
|
+
---
|
|
34
|
+
|
|
35
|
+
## Detailed Pitfalls & The 5-Point Rule
|
|
36
|
+
|
|
37
|
+
### 1. The 10-Field Interrogation Form
|
|
38
|
+
|
|
39
|
+
* **The Bad Habit:** Demanding full name, company name, company URL, job title, phone number, budget dropdown, industry, country, and message.
|
|
40
|
+
* **The Problem:** The contact form looks like a government tax audit. On a phone, the user has to scroll through 4 screens just to find the submit button.
|
|
41
|
+
* **Why It Fails:** Conversion drops by over 50% for every 2 extra fields added to a form. Mobile users will not type their corporate biography on a phone keyboard.
|
|
42
|
+
* **Clean Fix:** Cut the form down to 3 essential fields: Name, Email, and Message. You can always ask follow-up questions in your reply email:
|
|
43
|
+
```html
|
|
44
|
+
<form class="space-y-4 max-w-lg">
|
|
45
|
+
<div>
|
|
46
|
+
<label for="name" class="block text-sm font-medium text-neutral-700">Full Name</label>
|
|
47
|
+
<input type="text" id="name" required class="w-full mt-1 px-4 py-2.5 border border-neutral-300 rounded-lg focus:ring-2 focus:ring-neutral-900 outline-none">
|
|
48
|
+
</div>
|
|
49
|
+
<div>
|
|
50
|
+
<label for="email" class="block text-sm font-medium text-neutral-700">Email Address</label>
|
|
51
|
+
<input type="email" id="email" required class="w-full mt-1 px-4 py-2.5 border border-neutral-300 rounded-lg focus:ring-2 focus:ring-neutral-900 outline-none">
|
|
52
|
+
</div>
|
|
53
|
+
<div>
|
|
54
|
+
<label for="message" class="block text-sm font-medium text-neutral-700">Message</label>
|
|
55
|
+
<textarea id="message" rows="4" required class="w-full mt-1 px-4 py-2.5 border border-neutral-300 rounded-lg focus:ring-2 focus:ring-neutral-900 outline-none"></textarea>
|
|
56
|
+
</div>
|
|
57
|
+
<button type="submit" class="w-full py-3 bg-neutral-900 text-white font-medium rounded-lg hover:bg-neutral-800 transition">
|
|
58
|
+
Send Message
|
|
59
|
+
</button>
|
|
60
|
+
</form>
|
|
61
|
+
```
|
|
62
|
+
* **The Waitsec Way:** Respect user time. Ask only for what you need to start the conversation.
|
|
63
|
+
|
|
64
|
+
### 2. Stripping Input Focus Outlines
|
|
65
|
+
|
|
66
|
+
* **The Bad Habit:** Setting `outline: none` on inputs without replacing it with a custom focus ring.
|
|
67
|
+
* **The Problem:** When a user taps or tabs into an input box, the border looks completely unchanged.
|
|
68
|
+
* **Why It Fails:** The user cannot tell which field is currently active. On mobile devices with virtual keyboards, it leads to typing into the wrong box.
|
|
69
|
+
* **Clean Fix:** Always provide an unmistakable focus ring:
|
|
70
|
+
```css
|
|
71
|
+
/* Tailwind standard focus */
|
|
72
|
+
input:focus {
|
|
73
|
+
outline: none;
|
|
74
|
+
border-color: #171717;
|
|
75
|
+
box-shadow: 0 0 0 2px #171717;
|
|
76
|
+
}
|
|
77
|
+
```
|
|
78
|
+
* **The Waitsec Way:** Focus indicators guide the user's attention. Never disable them without providing a better one.
|
|
79
|
+
|
|
80
|
+
### 3. The Silent Ghost Submission
|
|
81
|
+
|
|
82
|
+
* **The Bad Habit:** When the user clicks "Send Message", nothing happens for 4 seconds, then the page reloads back to an empty form with no message.
|
|
83
|
+
* **The Problem:** The user has no idea whether the message went through or crashed. They click the button 5 more times in frustration.
|
|
84
|
+
* **Why It Fails:** Software must always confirm state changes. Silent forms destroy confidence and generate duplicate tickets.
|
|
85
|
+
* **Clean Fix:** Disable the submit button immediately on click, show a loading state, and render an unmistakable success card:
|
|
86
|
+
```html
|
|
87
|
+
<!-- Button Loading State: the spinner icon comes from the icon library, never inline SVG -->
|
|
88
|
+
<button disabled class="w-full py-3 bg-neutral-700 text-white font-medium rounded-lg cursor-not-allowed flex items-center justify-center gap-2">
|
|
89
|
+
<i data-lucide="loader-2" class="w-4 h-4 animate-spin"></i>
|
|
90
|
+
<span>Sending...</span>
|
|
91
|
+
</button>
|
|
92
|
+
|
|
93
|
+
<!-- Inline Success State -->
|
|
94
|
+
<div class="p-6 bg-green-50 border border-green-200 rounded-xl text-green-900">
|
|
95
|
+
<h3 class="font-bold">Message sent successfully!</h3>
|
|
96
|
+
<p class="text-sm mt-1 text-green-800">We received your note and will reply to your email within 24 hours.</p>
|
|
97
|
+
</div>
|
|
98
|
+
```
|
|
99
|
+
* **The Waitsec Way:** Never leave users guessing. Give immediate visual feedback for every user submission.
|
|
100
|
+
|
|
101
|
+
### 4. The Trapped Mobile Keyboard Viewport Shift
|
|
102
|
+
|
|
103
|
+
* **The Bad Habit:** Setting the contact container to fixed pixel height (`height: 600px`) or centering the form inside a strict `h-screen flex items-center`.
|
|
104
|
+
* **The Problem:** When the virtual on-screen keyboard pops up on a phone, the viewport height shrinks by 50%. The input field gets pushed behind the keyboard, and the user cannot see what they are typing.
|
|
105
|
+
* **Why It Fails:** Users cannot see their words, cannot review typos, and cannot reach the submit button.
|
|
106
|
+
* **Clean Fix:** Allow the page to scroll naturally. Use `min-h-screen` instead of `h-screen`, and give the form bottom padding (`pb-24`) so the submit button easily clears the virtual keyboard:
|
|
107
|
+
```html
|
|
108
|
+
<main class="min-h-screen py-12 px-4 sm:px-6 pb-32">
|
|
109
|
+
<div class="max-w-xl mx-auto">...</div>
|
|
110
|
+
</main>
|
|
111
|
+
```
|
|
112
|
+
* **The Waitsec Way:** Always account for virtual mobile keyboards. Content must scroll freely above the keyboard plane.
|
|
113
|
+
|
|
114
|
+
---
|
|
115
|
+
|
|
116
|
+
## SEO, GEO & Structured Data (Contact Page)
|
|
117
|
+
|
|
118
|
+
- Title: "Contact" plus the brand name, about 50 to 60 characters.
|
|
119
|
+
- Meta description: how to reach the team and the expected response time, about 140 to 160 characters.
|
|
120
|
+
- One `<h1>` such as "Get in touch".
|
|
121
|
+
- Print the email and address as visible text, not only inside the form, so they can be extracted.
|
|
122
|
+
- Server-render the contact details, the email link, and the response-time note.
|
|
123
|
+
- Keep the page focused on contact, and avoid unrelated marketing sections.
|
|
124
|
+
|
|
125
|
+
### JSON-LD for a Contact Page
|
|
126
|
+
|
|
127
|
+
```html
|
|
128
|
+
<script type="application/ld+json">
|
|
129
|
+
{
|
|
130
|
+
"@context": "https://schema.org",
|
|
131
|
+
"@type": "ContactPage",
|
|
132
|
+
"name": "Contact Us",
|
|
133
|
+
"url": "https://example.com/contact",
|
|
134
|
+
"mainEntity": {
|
|
135
|
+
"@type": "Organization",
|
|
136
|
+
"name": "Example Inc",
|
|
137
|
+
"url": "https://example.com",
|
|
138
|
+
"contactPoint": {
|
|
139
|
+
"@type": "ContactPoint",
|
|
140
|
+
"contactType": "customer support",
|
|
141
|
+
"email": "hello@example.com",
|
|
142
|
+
"availableLanguage": ["English", "Indonesian"]
|
|
143
|
+
}
|
|
144
|
+
}
|
|
145
|
+
}
|
|
146
|
+
</script>
|
|
147
|
+
```
|
|
148
|
+
|
|
149
|
+
Add the organization `logo` and a `PostalAddress` when a physical address is shown. Only include channels that are actually displayed on the page.
|
|
150
|
+
|
|
151
|
+
---
|
|
152
|
+
|
|
153
|
+
## Pre-Flight Checklist for Contact Pages
|
|
154
|
+
|
|
155
|
+
- [ ] Is the form limited to 3 or 4 essential fields (Name, Email, Message)?
|
|
156
|
+
- [ ] Does every input field have a visible label and high-contrast focus ring?
|
|
157
|
+
- [ ] Is there an immediate loading spinner on the submit button to prevent double-submits?
|
|
158
|
+
- [ ] Does the page display an unmistakable success banner after submission?
|
|
159
|
+
- [ ] Is there a direct, visible email address (`mailto:`) provided as an alternative contact method?
|
|
160
|
+
- [ ] Does the form have enough bottom padding to clear mobile virtual keyboards?
|
|
161
|
+
- [ ] Is there a valid ContactPage with Organization and ContactPoint schema?
|
|
162
|
+
- [ ] Are the email and address visible as text, not only inside the form?
|