Skip to content

Commit ddfd201

Browse files
authored
Merge pull request #13 from TOM-BOHN/sandbox
feat: About page enhancements and footer redesign
2 parents dd980bb + f737e05 commit ddfd201

13 files changed

Lines changed: 1149 additions & 198 deletions

File tree

CLOUD.md

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
# Cloud Agent Instructions
2+
3+
These instructions are for automated changes in this repository. The main
4+
priority is to keep the site building successfully after every change.
5+
6+
## Required checks (always run)
7+
8+
1. Install dependencies (if not already installed):
9+
- `npm install`
10+
2. Run the production build:
11+
- `npm run build`
12+
13+
## Build failure workflow (mandatory)
14+
15+
If the build fails, you must:
16+
17+
1. Read the full build output and identify the error source.
18+
2. Fix the error in code or configuration.
19+
3. Re-run `npm run build`.
20+
4. Repeat until the build succeeds.
21+
22+
Do not stop after a failed build. Keep iterating until it passes.
23+
24+
## Notes
25+
26+
- The `export` script is currently the same as `build`, so `npm run build`
27+
is the canonical check for release readiness.
28+
- If you are only changing content or links, the build is still required.

app/about/page.tsx

Lines changed: 181 additions & 38 deletions
Large diffs are not rendered by default.

app/links/page.tsx

Lines changed: 7 additions & 53 deletions
Original file line numberDiff line numberDiff line change
@@ -1,59 +1,13 @@
11
import { getLinks } from '@/lib/links'
2+
import { LinksPageWrapper } from '@/components/links/LinksPageWrapper'
23

34
export default async function Links() {
45
const links = await getLinks()
6+
const sections = Object.entries(links).map(([title, items]) => ({
7+
id: title,
8+
title,
9+
links: items,
10+
}))
511

6-
return (
7-
<div className="container mx-auto px-4 py-12">
8-
<div className="max-w-6xl mx-auto">
9-
<div className="mb-12">
10-
<p className="text-sm text-accent mb-4 font-mono">{'>'} SOFTWARE ENGINEER</p>
11-
<h1 className="text-2xl font-semibold mb-4 text-text-primary font-mono">
12-
{'// LINKS'}
13-
</h1>
14-
<p className="text-text-secondary leading-relaxed">
15-
Bookmarks, tools, and resources I find useful
16-
</p>
17-
</div>
18-
19-
{Object.keys(links).length === 0 ? (
20-
<div className="text-center py-12 border border-border rounded-lg bg-bg-secondary">
21-
<p className="text-text-secondary mb-4">No links organized yet.</p>
22-
<p className="text-text-secondary text-sm">
23-
Links will be organized by category here.
24-
</p>
25-
</div>
26-
) : (
27-
<div className="space-y-8">
28-
{Object.entries(links).map(([category, items]) => (
29-
<section key={category} className="border border-border rounded-lg p-6 bg-bg-secondary">
30-
<h2 className="text-2xl font-semibold mb-4 text-text-primary">
31-
{category}
32-
</h2>
33-
<ul className="space-y-3">
34-
{items.map((link) => (
35-
<li key={link.id}>
36-
<a
37-
href={link.url}
38-
target="_blank"
39-
rel="noopener noreferrer"
40-
className="text-link hover:text-link-hover underline flex items-center gap-2"
41-
>
42-
<span>{link.title}</span>
43-
{link.description && (
44-
<span className="text-text-secondary text-sm">
45-
- {link.description}
46-
</span>
47-
)}
48-
</a>
49-
</li>
50-
))}
51-
</ul>
52-
</section>
53-
))}
54-
</div>
55-
)}
56-
</div>
57-
</div>
58-
)
12+
return <LinksPageWrapper sections={sections} />
5913
}

app/page.tsx

Lines changed: 72 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,11 @@
1-
import Link from 'next/link'
21
import Image from 'next/image'
32

43
export default function Home() {
54
return (
65
<div className="container mx-auto px-4 py-12">
76
<div className="max-w-6xl mx-auto">
87
{/* Role tag */}
9-
<p className="text-sm text-accent mb-4 font-mono">{'>'} SOFTWARE ENGINEER</p>
8+
<p className="text-sm text-accent mb-4 font-mono">{'>'} PRODUCT MANAGER & SOFTWARE DESIGNER</p>
109

1110
{/* Main content area - two column layout */}
1211
<div className="grid md:grid-cols-2 gap-12 mb-16">
@@ -22,14 +21,16 @@ export default function Home() {
2221
</span>
2322
</h1>
2423
<p className="text-lg text-text-secondary leading-relaxed mb-4">
25-
Software engineer and technical leader specializing in Salesforce development,
26-
data engineering, and cloud architecture. Building scalable solutions and
27-
leading teams to deliver impactful technology solutions.
24+
Product manager and software designer specializing in AI products, data management,
25+
and analytics. I bridge product strategy with hands-on development, using software
26+
engineering tools and LLMs to define product details, explore ideas faster, and build
27+
proof-of-concepts that directly address customer needs.
2828
</p>
2929
<p className="text-lg text-text-secondary leading-relaxed">
30-
Currently working on enterprise-level Salesforce implementations and data
31-
warehouse solutions. Passionate about clean code, best practices, and
32-
mentoring the next generation of developers.{' '}
30+
Currently leading AI product initiatives at Salesforce, focusing on data management
31+
maturity and metadata AI solutions. Passionate about building data products that
32+
power trusted AI, and sharing insights on product strategy, data governance, and
33+
technical leadership.{' '}
3334
<a
3435
href="/contact"
3536
className="text-link hover:text-link-hover underline"
@@ -92,7 +93,36 @@ export default function Home() {
9293
<ul className="space-y-2 text-text-secondary">
9394
<li className="flex items-start gap-2">
9495
<span className="text-accent mt-1"></span>
95-
<span>Check out my latest articles on Medium</span>
96+
<a
97+
href="https://medium.com/@bohn.tl/the-4-cs-of-data-governance-measurement-5759fdbbc373"
98+
target="_blank"
99+
rel="noopener noreferrer"
100+
className="text-link hover:text-link-hover underline"
101+
>
102+
The 4 Cs of Data Governance Measurement
103+
</a>
104+
</li>
105+
<li className="flex items-start gap-2">
106+
<span className="text-accent mt-1"></span>
107+
<a
108+
href="https://medium.com/@bohn.tl/the-enabling-team-playbook-78b60b0bb4f0"
109+
target="_blank"
110+
rel="noopener noreferrer"
111+
className="text-link hover:text-link-hover underline"
112+
>
113+
The Enabling Team Framework
114+
</a>
115+
</li>
116+
<li className="flex items-start gap-2">
117+
<span className="text-accent mt-1"></span>
118+
<a
119+
href="https://medium.com/@bohn.tl/the-spec-driven-writing-framework-55facae16425"
120+
target="_blank"
121+
rel="noopener noreferrer"
122+
className="text-link hover:text-link-hover underline"
123+
>
124+
The Spec-Driven Writing Framework
125+
</a>
96126
</li>
97127
</ul>
98128
</div>
@@ -125,7 +155,36 @@ export default function Home() {
125155
<ul className="space-y-2 text-text-secondary">
126156
<li className="flex items-start gap-2">
127157
<span className="text-accent mt-1"></span>
128-
<span>Check out my repositories and contributions</span>
158+
<a
159+
href="https://github.com/TOM-BOHN/MsDS-deep-learing-gan-monet-painting/tree/main"
160+
target="_blank"
161+
rel="noopener noreferrer"
162+
className="text-link hover:text-link-hover underline"
163+
>
164+
deep-learing-gan-monet-painting
165+
</a>
166+
</li>
167+
<li className="flex items-start gap-2">
168+
<span className="text-accent mt-1"></span>
169+
<a
170+
href="https://github.com/TOM-BOHN/MsDS-deep-learing-cnn-cancer-detection"
171+
target="_blank"
172+
rel="noopener noreferrer"
173+
className="text-link hover:text-link-hover underline"
174+
>
175+
deep-learing-cnn-cancer-detection
176+
</a>
177+
</li>
178+
<li className="flex items-start gap-2">
179+
<span className="text-accent mt-1"></span>
180+
<a
181+
href="https://github.com/TOM-BOHN/MsDS-deep-learning-llm-classification-finetuning"
182+
target="_blank"
183+
rel="noopener noreferrer"
184+
className="text-link hover:text-link-hover underline"
185+
>
186+
deep-learning-llm-classification-finetuning
187+
</a>
129188
</li>
130189
</ul>
131190
</div>
@@ -160,12 +219,12 @@ export default function Home() {
160219
<span className="font-semibold text-text-primary">VIP + Beta program</span>.
161220
</p>
162221
<p className="text-text-secondary leading-relaxed">
163-
Interested in early access?{' '}
222+
Interested in early access? Contact{' '}
164223
<a
165-
href="/contact"
224+
href="mailto:hello@thomaslbohn.com"
166225
className="text-link hover:text-link-hover underline font-semibold"
167226
>
168-
Contact hello@thomaslbohn.com
227+
hello@thomaslbohn.com
169228
</a>
170229
{' '}to request access.
171230
</p>

components/Footer.tsx

Lines changed: 37 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -1,31 +1,55 @@
1+
import Link from 'next/link'
2+
import { FaGithub, FaLinkedin, FaEnvelope } from 'react-icons/fa'
3+
import { SiMedium } from 'react-icons/si'
4+
15
export function Footer() {
26
const currentYear = new Date().getFullYear()
37

48
return (
59
<footer className="border-t border-border bg-bg-secondary py-8 mt-auto">
6-
<div className="container mx-auto px-4">
7-
<div className="text-center text-text-secondary text-sm">
8-
<p>&copy; {currentYear} Thomas Bohn. All rights reserved.</p>
9-
<p className="mt-2">
10-
Built with{' '}
10+
<div className="container mx-auto px-4 max-w-7xl">
11+
<div className="text-text-secondary text-sm">
12+
{/* First row: Icons centered */}
13+
<div className="flex items-center justify-center gap-6 mb-4">
14+
<Link
15+
href="/contact"
16+
className="text-text-secondary hover:text-accent transition-colors"
17+
aria-label="Contact"
18+
>
19+
<FaEnvelope className="w-5 h-5" />
20+
</Link>
21+
<a
22+
href="https://www.linkedin.com/in/thomaslbohn/"
23+
target="_blank"
24+
rel="noopener noreferrer"
25+
className="text-text-secondary hover:text-accent transition-colors"
26+
aria-label="LinkedIn"
27+
>
28+
<FaLinkedin className="w-5 h-5" />
29+
</a>
1130
<a
12-
href="https://nextjs.org"
31+
href="https://medium.com/@bohn.tl"
1332
target="_blank"
1433
rel="noopener noreferrer"
15-
className="text-link hover:text-link-hover underline"
34+
className="text-text-secondary hover:text-accent transition-colors"
35+
aria-label="Medium"
1636
>
17-
Next.js
37+
<SiMedium className="w-5 h-5" />
1838
</a>
19-
{' '}and hosted on{' '}
2039
<a
21-
href="https://pages.github.com"
40+
href="https://github.com/TOM-BOHN"
2241
target="_blank"
2342
rel="noopener noreferrer"
24-
className="text-link hover:text-link-hover underline"
43+
className="text-text-secondary hover:text-accent transition-colors"
44+
aria-label="GitHub"
2545
>
26-
GitHub Pages
46+
<FaGithub className="w-5 h-5" />
2747
</a>
28-
</p>
48+
</div>
49+
{/* Second row: Copyright centered */}
50+
<div className="text-center">
51+
<p>&copy; {currentYear} Thomas Bohn. All rights reserved.</p>
52+
</div>
2953
</div>
3054
</div>
3155
</footer>

components/hub/HubSection.tsx

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ import {
1010
import {
1111
SiCredly,
1212
SiSalesforce,
13+
SiSubstack,
1314
} from 'react-icons/si'
1415

1516
interface HubSectionProps {
@@ -46,6 +47,13 @@ function getBrandIcon(linkId: string, linkTitle: string) {
4647
bgColor: '#f5f5f5'
4748
}
4849
}
50+
if (id.includes('substack') || title.includes('substack')) {
51+
return {
52+
icon: <SiSubstack className="w-8 h-8" />,
53+
color: '#ff6719',
54+
bgColor: '#fff5e6'
55+
}
56+
}
4957
if (id.includes('credly') || title.includes('credly')) {
5058
return {
5159
icon: <SiCredly className="w-8 h-8" />,

components/links/LinksHeader.tsx

Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,41 @@
1+
'use client'
2+
3+
interface LinksHeaderProps {
4+
onExpandAll: () => void
5+
onCollapseAll: () => void
6+
}
7+
8+
export function LinksHeader({ onExpandAll, onCollapseAll }: LinksHeaderProps) {
9+
return (
10+
<div className="flex items-center gap-1 border border-border rounded-lg bg-bg-primary p-1">
11+
<button
12+
onClick={onExpandAll}
13+
className="relative group p-1.5 text-accent hover:bg-bg-secondary rounded transition-colors"
14+
aria-label="Expand all sections"
15+
title="Expand all sections"
16+
>
17+
<svg className="w-4 h-4" fill="none" stroke="currentColor" viewBox="0 0 24 24">
18+
<path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M19 9l-7 7-7-7" />
19+
</svg>
20+
<span className="sr-only">Expand all</span>
21+
<span className="pointer-events-none absolute -bottom-8 left-1/2 -translate-x-1/2 whitespace-nowrap rounded border border-border bg-bg-primary px-2 py-1 text-xs text-text-primary opacity-0 shadow-sm transition-opacity group-hover:opacity-100 z-10">
22+
Expand all
23+
</span>
24+
</button>
25+
<button
26+
onClick={onCollapseAll}
27+
className="relative group p-1.5 text-accent hover:bg-bg-secondary rounded transition-colors"
28+
aria-label="Collapse all sections"
29+
title="Collapse all sections"
30+
>
31+
<svg className="w-4 h-4" fill="none" stroke="currentColor" viewBox="0 0 24 24">
32+
<path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M5 15l7-7 7 7" />
33+
</svg>
34+
<span className="sr-only">Collapse all</span>
35+
<span className="pointer-events-none absolute -bottom-8 left-1/2 -translate-x-1/2 whitespace-nowrap rounded border border-border bg-bg-primary px-2 py-1 text-xs text-text-primary opacity-0 shadow-sm transition-opacity group-hover:opacity-100 z-10">
36+
Collapse all
37+
</span>
38+
</button>
39+
</div>
40+
)
41+
}

0 commit comments

Comments
 (0)