Skip to content

Commit cdf842d

Browse files
authored
Update the README and site presentation (#3)
* docs: use a real screenshot for the README preview The file I kept in the last cleanup was not a screenshot at all: it was a generated placeholder card reading 'Service website for local businesses' in a slate blue that is not even in this site's palette. It is now an actual capture of the live homepage. * docs: rewrite the README in plain English Dropped the double-spaced hyphens left over from an earlier find and replace, and cut the listy summary and the reflective what-I-learned paragraph. It now leads with what the service actually is, admits the site is the easy part and the wording was the work, and carries the two gotchas that have actually caught me out: Netlify Forms does nothing on a local serve, and reaching the thanks page does not mean an email went anywhere. * fix: simplify backgrounds and protect the enquiry flow --------- Co-authored-by: Jamie Parr <JamieP-205@users.noreply.github.com>
1 parent c67ee1b commit cdf842d

7 files changed

Lines changed: 53 additions & 81 deletions

File tree

README.md

Lines changed: 27 additions & 60 deletions
Original file line numberDiff line numberDiff line change
@@ -2,85 +2,52 @@
22

33
[![CI](https://github.com/JamieP-205/local-web-fix/actions/workflows/ci.yml/badge.svg)](https://github.com/JamieP-205/local-web-fix/actions/workflows/ci.yml)
44

5-
## Live site
5+
Live at [localwebfix.co.uk](https://localwebfix.co.uk/).
66

7-
The service is live at [localwebfix.co.uk](https://localwebfix.co.uk/). Enquiries are delivered via Netlify Forms and followed up manually.
7+
A small service site. Local businesses send me a link to their website, Google listing or Facebook page, and I check whether a customer can actually find the basics: opening hours, the menu, a phone number that works on a phone, a booking link that is not dead.
88

9-
## Status
10-
11-
**Live service website** - this project is in production and used to accept enquiries from real clients.
12-
13-
## Summary
14-
15-
Local Web Fix is a focused service website offering practical website and online-information improvements for UK local businesses. Many small businesses already have a site, Google profile, menu, booking link or social page but customers still struggle to find basic information. This site positions my service around those specific problems: opening hours, contact routes, mobile clarity, menus, prices, services and inconsistent public details. It avoids fake testimonials, ranking promises or agency-style marketing and instead explains my scope and process clearly.
16-
17-
## Preview
18-
19-
![The Local Web Fix homepage on desktop and mobile](assets/local-web-fix-preview.png)
9+
![The Local Web Fix homepage](assets/local-web-fix-preview.png)
2010

2111
## Why I built it
2212

23-
I wanted to help local businesses fix the most important issues on their existing web presence without selling a full redesign they may not need. By offering targeted audits, clear handover templates and honest pricing, I can practise both technical and communication skills while studying.
24-
25-
## What I built
26-
27-
- A mobile-first service website with light and dark themes and a persistent theme preference
28-
- A Netlify Forms enquiry flow with required-field validation and a honeypot field to deter bots
29-
- Clear pricing, scope, access-safety and privacy information on dedicated pages
30-
- An unlisted payment page used only after a job scope is agreed
31-
- A fictional example audit that is clearly labelled as an example
32-
- Operating templates for audits, proposals, handovers and releases in `docs/`
33-
- A custom 404 page, sitemap, robots file, web manifest and social preview image
13+
Most small businesses do not need a rebuild. They need the details customers rely on to be correct and easy to find. This is my attempt to offer that smaller practical service while I build experience alongside university.
3414

35-
## Business thinking
15+
## The code is deliberately simple
3616

37-
This project forced me to think beyond code. I wrote copy that sets client expectations, created a pricing model that reflects the value of small fixes, established a safe process for accessing client sites without requesting passwords and built templates for audits and proposals. I also learned to keep the service honest: by making it clear I am a student and that I do not guarantee search-engine rankings or oversell my capacity, I build trust instead of hype.
17+
It is HTML, CSS and a theme toggle. The work went into the wording:
3818

39-
## Key files
19+
- **Pricing is on the page.** Free check, then £50, £100 or £150 with what each includes. No "contact us for a quote".
20+
- **The scope page says what I will not do.** No SEO campaigns, no payment systems, no plugin surgery. If another provider manages the site, I hand over notes rather than trying to take over.
21+
- **No passwords, ever.** The first check uses public links only. If a fix needs access later, it goes through proper collaborator or manager permissions. I am a student, and I should not be holding the logins to somebody's livelihood.
22+
- **The example check is labelled fictional**, because it is. It stays that way until a real business is happy for me to publish theirs.
4023

41-
- `index.html` - homepage and enquiry form
42-
- `privacy.html` - privacy information
43-
- `scope.html` - service boundaries and terms
44-
- `pay.html` - unlisted scope-confirmed payment links
45-
- `theme.js` - persisted light/dark theme preference
46-
- `docs/` - reusable operating templates and release notes
47-
- `tools/check-site.js` - site and link validation script used in CI
24+
## Files
4825

49-
## Technical approach
26+
- `index.html` the whole pitch, and the enquiry form
27+
- `scope.html` what is and is not included
28+
- `privacy.html` what happens to what people send me
29+
- `pay.html` payment links, unlisted and `noindex`, only sent once a scope is agreed
30+
- `theme.js` light/dark toggle, saved in localStorage
31+
- `docs/` templates I use for the actual work: audits, proposals, handovers
32+
- `tools/check-site.js` the checks CI runs
5033

51-
The project uses semantic HTML, CSS and a small vanilla JavaScript theme controller. There is no client-side framework because the site does not need one. The enquiry form is handled by Netlify Forms, which stores submissions and sends email notifications. The form never asks for passwords or account credentials. If later work needs access, the process uses limited collaborator or manager permissions where the platform supports them.
52-
53-
## Local development
34+
## Running it
5435

5536
```bash
5637
npm install
5738
npm test
5839
npx serve .
5940
```
6041

61-
No build step is required. `npm test` checks JavaScript syntax, required files, metadata, local links and the Netlify form configuration.
62-
63-
## Deployment checks
64-
65-
After a Netlify deployment I:
66-
67-
1. Submit a test enquiry
68-
2. Confirm it appears in Netlify Forms
69-
3. Verify the email notification
70-
4. Check the main information pages and a missing URL
71-
5. Confirm the payment page remains outside public navigation
72-
73-
## Privacy & safety notes
74-
75-
The service never stores or asks for passwords. All `.env` files and secrets are excluded from the repository. See [SECURITY.md](SECURITY.md) for vulnerability reporting and [CONTRIBUTING.md](CONTRIBUTING.md) for project rules.
76-
77-
## What I learned
42+
No build step. `npm test` parses the JavaScript, checks that required pages exist, verifies local links with exact filename casing and validates the full Netlify form setup. The form is the main conversion point, and a missing attribute can stop submissions without breaking the rest of the page.
7843

79-
By building Local Web Fix I learned how to scope and price a service, communicate limitations transparently, and design a simple website that gets clients to the enquiry stage without friction. I also gained practice in writing privacy policies, managing Netlify Forms, and thinking through client handover and access safety.
44+
## Gotchas
8045

81-
## Future improvements
46+
- The form is Netlify Forms, so it only works on a Netlify deploy. It does nothing on `npx serve`.
47+
- Reaching the thanks page does not prove an email went out. Netlify stores the submission either way, while email notifications are configured separately in the Netlify dashboard.
48+
- `pay.html` is deliberately not in the navigation or the sitemap. Do not link it.
8249

83-
- Collect anonymous feedback after each completed job to improve the service
84-
- Automate audit generation based on a checklist of common issues
85-
- Explore offering monthly monitoring as an optional add-on
50+
## Next
8651

52+
- A real example report, once a client is happy for me to publish one
53+
- Feedback after a finished job, so I have something better than my own opinion of how it went

assets/local-web-fix-preview.png

-15.2 KB
Loading

index.html

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -115,7 +115,7 @@ <h3>Your online details don’t match</h3>
115115
</div>
116116
</section>
117117

118-
<section id="example-check" class="section section-muted compact-section">
118+
<section id="example-check" class="section compact-section">
119119
<div class="container split-card example-check-card">
120120
<div>
121121
<p class="eyebrow">Example free check</p>
@@ -135,7 +135,7 @@ <h2>What you might get back.</h2>
135135
</div>
136136
</section>
137137

138-
<section id="setup" class="section section-muted compact-section">
138+
<section id="setup" class="section compact-section">
139139
<div class="container split-card">
140140
<div>
141141
<p class="eyebrow">Works with what you already use</p>
@@ -208,7 +208,7 @@ <h3>Full Fix-Up Plus</h3>
208208
</div>
209209
</section>
210210

211-
<section id="process" class="section section-muted compact-section">
211+
<section id="process" class="section compact-section">
212212
<div class="container section-head">
213213
<p class="eyebrow">How it works</p>
214214
<h2>Simple check, clear fix, safe access.</h2>
@@ -236,7 +236,7 @@ <h2>You stay in control.</h2>
236236
</div>
237237
</section>
238238

239-
<section id="about" class="section section-muted compact-section">
239+
<section id="about" class="section compact-section">
240240
<div class="container about-grid">
241241
<div class="portrait-card"><img src="/assets/jamie-parr.webp" width="640" height="640" alt="Jamie Parr, Computing Technologies student and founder of Local Web Fix." loading="lazy"></div>
242242
<div>

privacy.html

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -52,7 +52,7 @@ <h2>The short version</h2>
5252
<div class="container strip-grid">
5353
<div><strong>No selling data</strong><span>Your enquiry is used to reply and manage the request.</span></div>
5454
<div><strong>No passwords</strong><span>Access is handled through platform permissions where possible.</span></div>
55-
<div><strong>No tracking cookies</strong><span>No non-essential analytics cookies at launch.</span></div>
55+
<div><strong>No tracking cookies</strong><span>No non-essential analytics cookies.</span></div>
5656
</div>
5757
</section>
5858

@@ -87,7 +87,7 @@ <h2>Where it may be stored</h2>
8787
</div>
8888
</section>
8989

90-
<section class="page-section section-muted">
90+
<section class="page-section">
9191
<div class="container page-split">
9292
<div>
9393
<p class="eyebrow">Access</p>
@@ -104,7 +104,7 @@ <h2>If platform access is needed</h2>
104104
<div class="container two-card-grid">
105105
<article class="info-card">
106106
<h2>Cookies and analytics</h2>
107-
<p>This site does not use non-essential analytics cookies at launch. If analytics or tracking is added later, this page will be updated to explain what is used and why.</p>
107+
<p>This site does not use non-essential analytics cookies. If analytics or tracking is added later, this page will be updated to explain what is used and why.</p>
108108
</article>
109109
<article class="info-card">
110110
<h2>Deleting information</h2>
@@ -129,4 +129,4 @@ <h2>Deleting information</h2>
129129
</footer>
130130
<script src="/theme.js" defer></script>
131131
</body>
132-
</html>
132+
</html>

scope.html

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -65,7 +65,7 @@ <h2>The simple rule</h2>
6565
</div>
6666
</section>
6767

68-
<section class="page-section section-muted">
68+
<section class="page-section">
6969
<div class="container page-split">
7070
<div>
7171
<p class="eyebrow">Included</p>
@@ -98,7 +98,7 @@ <h2>Access and passwords</h2>
9898
</div>
9999
</section>
100100

101-
<section class="page-section section-muted">
101+
<section class="page-section">
102102
<div class="container page-split">
103103
<div>
104104
<p class="eyebrow">Not included</p>

styles.css

Lines changed: 2 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -91,6 +91,8 @@ svg {
9191
max-width: 100%;
9292
}
9393

94+
img { height: auto; }
95+
9496
p {
9597
margin: 0;
9698
max-width: 66ch;
@@ -184,10 +186,6 @@ ul {
184186
padding: clamp(2.8rem, 7vw, 5rem) 0;
185187
}
186188

187-
.section-muted {
188-
background: var(--bg-alt);
189-
}
190-
191189
.section-head {
192190
margin-bottom: 1.6rem;
193191
}
@@ -782,10 +780,6 @@ details p {
782780

783781
/* 10. Contact form */
784782

785-
.form-section {
786-
background: var(--bg-alt);
787-
}
788-
789783
.form-layout {
790784
display: grid;
791785
gap: 1.3rem;
@@ -972,7 +966,6 @@ details p {
972966

973967
.compact-info-strip {
974968
padding: 1rem 0;
975-
background: var(--bg-alt);
976969
}
977970

978971
.strip-grid {

tools/check-site.js

Lines changed: 14 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -59,8 +59,20 @@ for (const required of ["index.html", "404.html", "privacy.html", "scope.html",
5959
}
6060

6161
const homepage = fs.readFileSync(path.join(root, "index.html"), "utf8");
62-
if (!/name=["']quick-review["']/i.test(homepage) || !/data-netlify=["']true["']/i.test(homepage)) {
63-
errors.push("index.html must contain the Netlify quick-review form");
62+
const quickReviewForm = homepage.match(/<form\b(?=[^>]*\bname=["']quick-review["'])(?=[^>]*\bmethod=["']POST["'])(?=[^>]*\baction=["']\/thanks\.html["'])(?=[^>]*\bdata-netlify=["']true["'])(?=[^>]*\bnetlify-honeypot=["']bot-field["'])[^>]*>([\s\S]*?)<\/form>/i);
63+
if (!quickReviewForm) {
64+
errors.push("index.html must contain the complete Netlify quick-review form setup");
65+
} else {
66+
const formBody = quickReviewForm[1];
67+
if (!/<input\b(?=[^>]*\btype=["']hidden["'])(?=[^>]*\bname=["']form-name["'])(?=[^>]*\bvalue=["']quick-review["'])[^>]*>/i.test(formBody)) {
68+
errors.push("quick-review must include its hidden form-name field");
69+
}
70+
if (!/<input\b(?=[^>]*\bname=["']bot-field["'])[^>]*>/i.test(formBody)) {
71+
errors.push("quick-review must include its honeypot input");
72+
}
73+
if (!/<input\b(?=[^>]*\btype=["']hidden["'])(?=[^>]*\bname=["']subject["'])(?=[^>]*\bdata-remove-prefix\b)[^>]*>/i.test(formBody)) {
74+
errors.push("quick-review must keep the version-controlled notification subject");
75+
}
6476
}
6577

6678
if (errors.length) {

0 commit comments

Comments
 (0)