A modern, responsive portfolio website built with Next.js and deployed on Cloudflare Workers using OpenNext. Features real-time data integration with Credly, Microsoft Learn, and TryHackMe APIs.
- π¨ Modern Design: Clean, professional portfolio with dark mode support
- π Live Data: Real-time certifications and skills from Credly API
- π Microsoft Learn Integration: Live progress tracking from Microsoft Learn
- π TryHackMe Integration: Real-time cybersecurity learning stats and achievements
- π Blog System: Complete blog functionality with markdown support and dynamic content generation
- π± Responsive: Optimized for all devices and screen sizes (mobile-first design)
- βΏ Accessible: Built with accessibility in mind using Radix UI components
- β‘ Fast: Deployed on Cloudflare Workers for global performance
- π Dark Mode: Automatic dark/light mode detection with smooth transitions
- π Automated Content: Blog posts automatically generated from markdown files
- βοΈ Framework: Next.js 15 with App Router
- π¨ Styling: Tailwind CSS with custom dark mode support
- π§© UI Components: Radix UI for accessible, unstyled components
- βοΈ Deployment: Cloudflare Workers via OpenNext
- π APIs:
- Credly API for certifications and skills
- Microsoft Learn API for progress tracking
- TryHackMe API for cybersecurity achievements
- π Content Management:
- Markdown-based blog posts with frontmatter
- Gray-matter for metadata parsing
- Custom markdown-to-HTML conversion
- π― Icons: FontAwesome for social media and UI icons
- π¦ Package Manager: pnpm for faster, more efficient dependency management
- Node.js 18+
- pnpm (recommended) or npm
- Cloudflare account (for deployment)
- Clone the repository:
git clone <repository-url>
cd portfolio- Install dependencies:
pnpm install- Generate blog data (if you have blog posts):
pnpm generate-blog- Run the development server:
pnpm devOpen http://localhost:3000 with your browser to see the result.
The build process automatically generates blog data:
pnpm buildThis command will:
- Generate blog data from markdown files
- Build the Next.js application
- Prepare for deployment
To test the Cloudflare Workers deployment locally:
pnpm previewThis will start the OpenNext build process and run the app using Wrangler dev server.
- Make sure you have Wrangler CLI installed and authenticated:
npm install -g wrangler
wrangler login- Deploy the application:
pnpm deployThis command will:
- ποΈ Build the Next.js application using OpenNext
- βοΈ Deploy it to Cloudflare Workers
- π Make it available at your configured domain
The application uses the following external APIs:
- π Credly API: For fetching certifications and skills
- π Microsoft Learn API: For fetching learning progress
- π TryHackMe API: For fetching cybersecurity achievements and stats
No API keys are required as these are public endpoints.
src/
βββ app/ # Next.js App Router
β βββ api/ # API routes
β β βββ certifications/ # Credly API proxy
β β βββ ms-learn/ # Microsoft Learn API proxy
β β βββ tryhackme/ # TryHackMe API proxy
β βββ blog/ # Blog pages and routing
β β βββ [id]/ # Dynamic blog post pages
β β βββ [slug]/ # Alternative slug-based routing
β β βββ page.tsx # Blog listing page
β βββ globals.css # Global styles
β βββ layout.tsx # Root layout
β βββ page.tsx # Home page
βββ components/ # React components
β βββ ui/ # Radix UI components
β β βββ badge.tsx # Badge component
β β βββ card.tsx # Card component
β β βββ checkmark-badge.tsx # Checkmark badge
β β βββ empty-state.tsx # Empty state component
β β βββ error-state.tsx # Error state component
β β βββ hover-card.tsx # Hover card component
β β βββ loading-state.tsx # Loading state component
β β βββ section-container.tsx # Section container
β β βββ section-header.tsx # Section header
β βββ creds.tsx # Certifications component
β βββ skills.tsx # Skills component
β βββ progress.tsx # Microsoft Learn progress
β βββ tryhackme.tsx # TryHackMe stats component
β βββ socials.tsx # Social media links
β βββ useCertifications.ts # Custom hook for data fetching
βββ content/ # Content management
β βββ blog/ # Blog post markdown files
β βββ getting-started-with-cybersecurity.md
β βββ microsoft-learn-journey.md
β βββ tryhackme-learning-path.md
βββ data/ # Generated data files
β βββ blog-posts.json # Processed blog posts data
βββ hooks/ # Custom React hooks
β βββ useApiData.ts # Generic API data fetching hook
βββ lib/ # Utility functions
β βββ api.ts # API utility functions
β βββ utils.ts # Tailwind CSS utilities
βββ scripts/ # Build and deployment scripts
β βββ generate-blog-data.js # Blog data generation
β βββ deploy-cloudflare.js # Cloudflare deployment
β βββ preview-cloudflare.js # Local Cloudflare preview
βββ styles/ # Additional styles
β βββ responsive.css # Responsive design utilities
βββ types/ # TypeScript type definitions
βββ index.ts # Shared type definitions
Proxies requests to the Credly API to fetch certifications and skills data.
Proxies requests to the Microsoft Learn API to fetch learning progress and achievements.
Proxies requests to the TryHackMe API to fetch cybersecurity achievements and statistics.
The portfolio includes a complete blog system with the following features:
- Markdown Support: Write posts in markdown with frontmatter metadata
- Automatic Generation: Blog data is generated from markdown files during build
- Dynamic Routing: Posts are accessible via
/blog/[slug]URLs - Metadata Support: Title, description, date, tags, author, and read time
- Create a new
.mdfile insrc/content/blog/ - Add frontmatter metadata:
---
title: "Your Post Title"
description: "Brief description"
date: "2024-12-01"
tags: ["tag1", "tag2"]
author: "Stephen Freerking"
readTime: "5 min read"
---
Your markdown content here...- Run
pnpm generate-blogto process the new post - The post will be available at
/blog/your-post-slug
The generate-blog-data.js script:
- Processes all markdown files in
src/content/blog/ - Converts markdown to HTML with syntax highlighting
- Extracts frontmatter metadata
- Generates
src/data/blog-posts.jsonwith all post data - Sorts posts by date (newest first)
- Responsive design with mobile-first approach
- Syntax highlighting for code blocks
- Consistent typography and spacing
- Dark mode support
- Accessible navigation and reading experience
Certifications are automatically fetched from your Credly profile. No manual updates required.
Skills are extracted from your certifications and automatically deduplicated.
The application uses Tailwind CSS with custom dark mode support. Modify src/app/globals.css and component styles as needed.
The portfolio is built with a mobile-first approach and includes:
- Responsive grid layouts for certifications (1-5 columns based on screen size)
- Adaptive typography and spacing
- Touch-friendly interactive elements
- π Global CDN: Deployed on Cloudflare's global network
- β‘ Edge Computing: Server-side rendering at the edge
- π¦ Optimized Assets: Images and fonts are optimized automatically
- πΎ Caching: Intelligent caching for API responses
- π Fast Loading: Optimized bundle sizes and lazy loading
- π Eliminated Code Duplication: Removed duplicate loading and error states across components
- π§© Reusable UI Components: Created standardized UI components for consistent design
- π¦ Centralized Type Definitions: Improved type safety with shared interfaces
- π― Standardized Data Fetching: Generic
useApiDatahook for consistent API handling - π Better Organization: Cleaner file structure and import patterns
- π Complete Blog Functionality: Full markdown-based blog system
- π Automated Content Generation: Scripts for processing blog posts
- π¨ Blog Styling: Responsive design with syntax highlighting
- π Dynamic Routing: SEO-friendly blog post URLs
- π± Enhanced Responsiveness: Improved centering and layout on all screen sizes
- π― Better Grid Layout: Optimized certification grid with proper centering
- β‘ Performance Optimizations: Reduced bundle size and improved loading times
- π Dark Mode Polish: Enhanced visual design and user experience
- π΄ Fork the repository
- πΏ Create a feature branch
- βοΈ Make your changes
- π§ͺ Test thoroughly
- π€ Submit a pull request
This project is private and proprietary.
For questions or issues, please contact Stephen Freerking.
Built with β€οΈ using Next.js and Cloudflare Workers π