-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathindex.html
More file actions
257 lines (238 loc) · 13 KB
/
index.html
File metadata and controls
257 lines (238 loc) · 13 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta name="description" content="Bob Davies - Web Developer">
<title>Bob Davies | Web Developer</title>
<link rel="preconnect" href="https://fonts.googleapis.com">
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
<link href="https://fonts.googleapis.com/css2?family=VT323&display=swap" rel="stylesheet">
<link rel="shortcut icon" href="favicon.ico" type="image/x-icon">
<link rel="icon" href="favicon.ico" type="image/x-icon">
<link rel="stylesheet" type="text/css" href="style.css">
<link rel="stylesheet" type="text/css" href="scrollbar.css">
</head>
<body>
<div class="wrapper">
<div class="content">
<div id="screen" class="screen" aria-live="polite"></div>
<noscript>
<pre> **** COMMODORE 64 BASIC V2 ****
64K RAM SYSTEM 38911 BASIC BYTES FREE
READY.
10 PRINT "Bob Davies likes coding"
(Enable JavaScript for navigation.)</pre>
</noscript>
</div>
</div>
<script>
// Add new sections/pages by extending DATA (new key -> new section).
const DATA = {
info: [
{
title: "Intro",
body: [
"I'm Bob. I build software and I like keeping things simple.",
"I enjoy side projects, games, guitar and nerd stuff.",
"I work wood; carving, turning, a little bit of other crafts too."
].join("\n"),
},
{
title: "Work Experience",
body: [
"Milk rounds, paper rounds, second hand shop/market arbitrage, estate fencing (not estate fencing, lol, you know what I mean), then ran a Sunday/seasonal market stall from 14-17, hustler-kid.",
"Built databases and spreadsheets (mostly Lotus and DOS tabbers, smart sheets, MS Access, some Oracle) for local businesses, built a freelance client base fixing the millenium bug and shipping ~£99 websites",
"Earned a middling degree from an okay uni (the course was actually pretty useful, almost polytechnic), failed to join the RAF, but found a decent first year real™ job doing VB and early C# near Manchester",
"Got a better job for a large management consultancy, and enjoyed travelling the country (some overseas, including on the Palm Jumeirah and some skyscrapers in Dubai) fixing problems for large infrastructure projects",
"Worked on Edinburgh tram, East London line, the UK's flood warning system, and various boring infrastructure projects (mostly custom software solutions, tool/workflow integrations, some clever-clogs stuff, mostly 'big team' stuff). Won some internal awards, but wasn't really anywhere more technical to _go_ (no interest in going into management), and corpo work moves painfully slowly as staff numbers grow.",
"Left to work for myself and build software around Manchester. Mainly web and mobile apps, tools, games, some cool experiments/prototypes for local start-ups",
"You can use code I worked on the NICE BNF (British National Formulary) or HDAS (Healthcare Databases Advanced Search) tools, or by using the app for whoever does your smart light bulbs or your phone provider's usage tracker, or by playing Video Poker, Keno or various other casino games in the back of seedy bars or on cruise ships",
"Side-lined into Microstock photography and passive income (I sell quite a lot of t-shirts online) between contracts, built picWorkflow and related tools with modest user bases. Travelled to Moscow, Berlin and Dublin giving talks on industry/tech until Brexit and the choking of that industry",
"I pick up a contract occasionally nowadays, but I'm picky about what takes up time I could be using for my own work. I just really love building things.",
"Currently I'm enjoying learning what AI can and can't do. I don't really have any conclusions yet."
].join("\n"),
},
{
title: "FAQ",
body: [
"Q: Are you available for work?",
"A: Sometimes. I'm probably not very interested in your stack though, the cloud-first stuff is more admin than interesting code.",
"Q: What do you build?",
"A: Web apps, tools, games, toys, whatever. Most of my stuff would fall under production tool nowadays",
"Q: Why the Commodore 64 look?",
"A: I got bored of the usual corpo themes and I like anti-design",
].join("\n"),
},
],
links: [
{ title: "bsky/bobbigmac", href: "https://bsky.app/profile/bobbigmac.bsky.social" },
{ title: "bobbigmac.com", href: "https://bobbigmac.com", note: "My blog" },
{ title: "github/bobbigmac", href: "https://github.com/bobbigmac" },
{ title: "reddit/bobbigmac", href: "https://www.reddit.com/user/bobbigmac" },
{ title: "youtube/@BobDavies1", href: "http://youtube.com/@BobDavies1", note: "Classic audiobooks, some content experiments" },
{ title: "Better Britain", href: "https://betterbritain.org.uk", note: "Experimenting with 'AI as a research tool for good??'" },
],
movies: [
{ title: "Alien", review: "It's good innit" },
{ title: "Blade Runner", review: "The best film ever made, until age 25 when I noticed it's paced SLOOOOW and its themes are a bit thin" },
{ title: "Mad Max: Fury Road", review: "Sandy af." },
{ title: "Star Trek: Insurrection", review: "My fave trek movie cos it's the one most like an episode of TNG" },
{ title: "Day of the Dead", review: "There is a zombie called Bob. He likes listening to music through his headphones." },
{ title: "Independence Day", review: "I'm bacccckkkkk!!!!" },
{ title: "The Belko Experiment", review: "I like those cheap horrors where it's the system that fights the people, until they figure it out" },
],
games: [
{ title: "Hitman 1-2-3 (now WoA)", review: "Great for completionists, so many challenges." },
{ title: "Quake 2", review: "The only perfect game (except maybe for Unpacking)" },
{ title: "World of Warcraft", review: "I quit in 2014, then again for good in 2019, when it helped me quit smoking." },
{ title: "Moraff's Dungeon", review: "The first fully fleshed out virtual world I remember exploring (played on on a 1-bit display)" },
{ title: "DOOM (2016)", review: "Pew pew pew" },
{ title: "MGSV", review: "Nuclear disarmament simulator, collecting action men like panini stickers" },
{ title: "Commandos", review: "Still never managed to beat the Beyond the Call of Duty standalone DLC campaign" },
{ title: "Starflight", review: "Space games are pretty complicated nowadays, this just isn't that complicated" },
],
music: [
{ title: "Portishead", review: "Chill, always reminds me of Buffy the Vampire Slayer." },
{ title: "Radiohead", review: "My go to 'leave me alone' music." },
{ title: "Muse", review: "Some girl once looked me up and down in the pub and said 'I bet you like Muse', which was of course true" },
{ title: "Ice T", review: "The OG. Home Invasion has yet to be topped" },
{ title: "Radio 3", review: "Gimme a rainy evening and a Petroc Trelawny in my ear" },
{ title: "Johann Johannsson", review: "Miner's hymns and IBM 1401 follow me round" },
{ title: "Playing", review: "I play a little guitar and keyboard/organ. I'm not very good, but I enjoy it." },
],
"dev-platforms": [
{ title: "Meteor", review: "This is just so my jam, I wish I could use 0.12beta forever." },
{ title: "Angular", review: "Such a dead platform, if you ask me about this, I will tell you to throw it away" },
{ title: "React", review: "If React is so great, why is every website built with it a usability nightmare? It makes managing complex code better, at the cost of the user experience." },
{ title: "Next", review: "Good idea, but you probably just needed a static html file and a github action" },
{ title: "Vue", review: "I like it, but just use google sheets already, you don't need a website ;)" },
{ title: "Node", review: "Pretty much what I think in, since it beat out C#." },
{ title: "Python", review: "Significant whitespace? I suppose, if we absolutely have to" },
{ title: "Ruby", review: "Not do or do, try no is There" },
{ title: "Rust", review: "Fast and neat, but I'm not sure if it's worth the hassle." },
{ title: "PHP", review: "Still probably the best platform for most websites, that I haven't used for a decade" },
{ title: "Java", review: "For when I want a headache. Sorry, I meant: when I want a HeadacheFactory. I once made a Java-based product that sold for a million quid. Didn't see any of it, but did get a certificate :p" },
{ title: "C#", review: "When you're the type of person who schedules a meeting that could have been an email. I used to think in C#, but I didn't like LINQ very much" },
{ title: "C++", review: "I write this occasionally, but always with trepidation because it usually kicks my butt" },
],
podcasts: [
{ title: "Bob's Favourite Podcasts", href: "https://bobdavies.co.uk/podcasts/" },
{ title: "Mom Can't Cook", review: "I've never seen any of the films they recap." },
{ title: "Second Wind", review: "Various podcasts: Firelink, Windbreaker (lol) and Rewind." },
{ title: "Oxventure", review: "D&D without the faffing about, good well-contained episodes with fun characters." },
{ title: "Apocalypse Players", review: "Actual-play with great pacing and atmosphere. I like that they don't dumb it down, and the sound editing is great." },
],
};
const screen = document.getElementById("screen");
const titleCase = (s) => (s || "").replace(/[-_]+/g, " ").replace(/\b\w/g, (c) => c.toUpperCase());
const escapeHtml = (s) => String(s).replace(/[&<>"']/g, (ch) => ({ "&": "&", "<": "<", ">": ">", '"': """, "'": "'" }[ch]));
const slugify = (s) =>
String(s)
.toLowerCase()
.trim()
.replace(/['"]/g, "")
.replace(/[^a-z0-9]+/g, "-")
.replace(/^-+|-+$/g, "") || "item";
function buildIndex(data) {
const index = {};
for (const [type, items] of Object.entries(data)) {
const used = new Map();
index[type] = [];
for (let i = 0; i < items.length; i++) {
const item = items[i];
const base = slugify(item.title || `item-${i + 1}`);
const n = (used.get(base) || 0) + 1;
used.set(base, n);
const slug = n === 1 ? base : `${base}-${n}`;
index[type].push({ ...item, slug, type });
}
}
return index;
}
const INDEX = buildIndex(DATA);
function setLines(lines) {
screen.replaceChildren();
for (const line of lines) {
const el = document.createElement("div");
el.className = "line";
el.innerHTML = line;
screen.appendChild(el);
}
}
function parseRoute() {
const raw = (location.hash || "").replace(/^#\/?/, "");
return raw.split("/").filter(Boolean).map(decodeURIComponent);
}
function renderHome() {
const types = Object.keys(DATA);
const lines = [
` **** COMMODORE 64 BASIC V2 ****`,
` 64K RAM SYSTEM 38911 BASIC BYTES FREE`,
``,
`READY.`,
//`10 PRINT "Bob Davies likes coding"`,
...types.map((t) => `- <a href="#/${encodeURIComponent(t)}">${escapeHtml(titleCase(t))}</a>`),
];
setLines(lines);
}
function renderType(type) {
const items = INDEX[type];
if (!items) return renderNotFound();
const lines = [
`**** ${escapeHtml(titleCase(type))} ****`,
``,
...items.map((item, i) => {
const n = String(i + 1).padStart(2, "0");
const label = escapeHtml(item.title);
if (item.href) {
const note = item.note ? ` — ${escapeHtml(item.note)}` : "";
return `${n}. <a href="${escapeHtml(item.href)}">${label}</a>${note}`;
}
return `${n}. <a href="#/${encodeURIComponent(type)}/${encodeURIComponent(item.slug)}">${label}</a>`;
}),
``,
`<a href="#/">Back</a>`,
];
setLines(lines);
}
function renderItem(type, slug) {
const items = INDEX[type];
if (!items) return renderNotFound();
const item = items.find((x) => x.slug === slug);
if (!item) return renderNotFound();
if (item.href) {
const note = item.note ? `<br><br>${escapeHtml(item.note)}` : "";
setLines([
`**** ${escapeHtml(item.title)} ****`,
``,
`<a href="${escapeHtml(item.href)}">Open</a>${note}`,
``,
`<a href="#/${encodeURIComponent(type)}">Back</a>`,
]);
return;
}
const text = item.body ?? item.review ?? item.content ?? "";
const body = String(text).split("\n").map(escapeHtml).join("<br>");
setLines([
`**** ${escapeHtml(item.title)} ****`,
``,
body || `(no content)`,
``,
`<a href="#/${encodeURIComponent(type)}">Back</a>`,
]);
}
function renderNotFound() {
setLines([`**** NOT FOUND ****`, ``, `Try <a href="#/">Home</a>.`]);
}
function route() {
const parts = parseRoute();
if (parts.length === 0) return renderHome();
if (parts.length === 1) return renderType(parts[0]);
return renderItem(parts[0], parts[1]);
}
window.addEventListener("hashchange", route);
route();
</script>
</body>
</html>