Skip to main content

Build landing page using TailwindUI and Next.js

· 4 min read
Software Engineer

My tennis coach wants a landing page for his company, I 'built' one using TailwindUi and Next.js in one day.

Why TailwindUI

Last time I wrote a website outside work I was still using BootStrap with Angular1. Most companies I worked for have internal frameworks and design systems so there is not much to think about. For my blog site I just used docsaursus and it ships with its own UI framework Infima. For a landing page I need something fancy like all the cool kids.

I heard about tailwindcss a lot, google around and found their paid product TailwindUI. For me, I want a template with a lot of built-in components, I don't want to learn how to build my own design systems from scratch. The price (after tax) is about $400 CAD, which is not cheap. But considering the time I saved from searching free alternative and build equivalent components on my own. I feel spend the money is better than pounding my head on the wall for a week and giving up with a unfinished website.

Why Next.js

I actually never used Next.js before, I tried gatsby and docusaurus for my blog site. The main reason is TailwindUI offers template using Next.js. All I want is copy and paste, plus there is support for Next.js in cloudflare pages, so I don't need to learn Vercel and deploy things in two places.

The building process

Or we should call it the copy and paste process...

  • First buy the product, I chose all access. I feel they just price the individual component/templates in a way that make you want to buy the all access version.

Read the doc

  • The official doc doesn't say much, just what you should install via npm install, fonts etc.
  • Each template offers a zip download, which provides javascript and typescript version. I choose typescript.
  • Each component offers the code to copy and paste, though it is not full code. While there are multiple items in previews, code snippet only have one item data and a for loop.

Init new project

I plan to deploy using cloudflare pages, so I created initial Next.js project. See Connect GitHub repo to Cloudflare Pages If you are using Vercel, you should be able to use the template directly by pushing it to a github repo and configuring Vercel accordingly.

Copy the template

First run my empty Next.js project and the template project side by side.

Set different port in package.json

"scripts": {
"dev": "next dev -p 4020",
"build": "next build",
"start": "next start -p 4020",
",,,": "...."

The missing dependencies in pages

  • tailwindcss@latest, cloudflare uses 3.3
  • @tailwindcss/forms to reset form styles
  • @headlessui/react
  • @headlessui/tailwindcss
  • clsx for construct className

Cloudflare also have api for workers (edge function), but I am not using it right now, so I will keep the existing hello world.

Then copy everything to the src folder, you should see everything in the template working in you cloudflare created repo.

Copy components

For example, I want the team section on the landing page.

Update title and meta

Add a new page


Git push.


In the end it took 3 hours to have the MVP going live. If I were still back at school, I would definitely pick some free UI toolkits, build the layout and components step by step for a week. After working for a couple of years and gave up on multiple side projects. I feel delivery is more important, if myself and users cannot see a viable product in a reasonable time. We all gave up... The timely positive feedback matters. The mindset of building something is different from learning for fun. When building a product, focus should be on the unique part of the project, this applies both to product itself and its tech stack.

Connect GitHub Repo to Cloudflare Pages

· 2 min read
Software Engineer

You have to connect to github before creating the page. You cannot connect on existing page.

Why connect to GitHub?

When using cloudflare pages, you can publish your build manually using the wrangler cli. This works when you rarely update the site. However, if you just want to write stuff, push to github and let it deploy automatically like github pages and netlify, you need to connect to github.

The main annoyance is that you cannot connect to github after creating the page. However, when you run the cli to create the initial code e.g. npm create cloudflare@latest my-next-app -- --framework=next it will create the page automatically. So you have to first create a github repo, and connect to it in the pages dashboard to create the pages, then add the actual code.


  • Create a github repo, just create a empty one on like myapp
  • When creating the page repo set --deploy false. For example, run the following in ~/dev
npm create cloudflare@latest myapp -- --framework=next --deploy false
  • In ~/dev/myapp run the following to preview the website
npm run dev
  • Push to github, the c3 cli already did git commit, the branch is already main so you don't need to rename it using git branch -M main
git remote add origin [email protected]:yourname/myapp.git
git push -u origin main
  • Create Application from Workers & Pages sidebar
    • Select Pages tab, default is Workers
    • Connect to Git
    • Select the repo
    • Select the framework you used when creating the app, e.g. next

Then cloudflare will do the first deploy and subsequent deploys when you push to github's main branch.

Learn Python with Friend: The Beginning

· 4 min read
Software Engineer

My friend working at a bank wanted to learn Python and I (using Java at work) wanted to learn Python again for machine learning. I thought I could learn python better by teaching another person. I figured it might help people with similar background (e.g. teach your partner who wants to try software related jobs), so I decided to write a series of blog posts to document the 'course' I designed and material used.


There are many python tutorial, book and open courses online, but I want to design a course that is more related to my friend's background (working at bank) so he can practice using things he learned and find the knowledge useful and get into a positive feedback loop. Otherwise, I would be forcing him to recite concepts and telling him these will be used eventually like my calculus teacher in university.

He learned programming when he was at university a decade ago and now he only remembers HTML... So the plan is to start from the very basic and cover the daily tooling of a software engineer such as using terminal, git/github, writing markdown. Tooling related with programming is a very curial part that I found missing in intro courses back at university. Version track, write document is not only important for collaborating with other people at work, it is also important for side project with only one author (and one user...) because you may pick the project up one year later and need to figure out what your were doing ASAP before you give up again.

The syllabus is divided into chapters, though length of content increases in later chapters. The schedule is 3h offline sync per week and there was no plan on when we will finish. I will adjust the content based on our progress.

Prepare development environment

  • Terminal
    • common shell commands, ls, cd, cat, vi
    • accepting input and output from command line
    • make the calculator an executable you can run like other programs
  • Git and GitHub
    • Create a GitHub account
    • Track code using git from GUI/terminal
    • Use GitHub codespace, vscode for both local and remote development
  • Use the REPL, run python file and Jupiter Notebook

Language itself

  • Hello world using a tax/mortgage calculator
    • variable
    • control flow, if, for
    • function, argument, return, scope of variables inside function
  • Basic data structure for tracking a person's monthly expense
    • list
    • dict
    • draw plot, if it works w/o Jupyter Notebook then we can still stick with cli
  • Class, model behavior of a company, e.g. generic employee, manager, worker, ceo etc.


  • brute force
  • complexity, O(N)
  • recursion
  • binary search (for dive and conquer)
  • dfs/bfs on graph/tree (we can use dict and switch to class later)
  • LeetCode


  • Test, unit test
  • Package, dependency and version management


  • Web
    • Crawl other website
    • A simple web service
      • Make previous mortgage calculator a website
      • use other packages
    • Use a database, use sqlite because we introduce docker later
      • First start with implementing everything in memory and see if it will cause any issue (gone after restart)
  • Cloud
    • Docker for development and packaging
    • Deploy the website to GCP/AWS using free tier
  • ML, predict person spending, stock price etc.
    • Jupyter Notebook
    • numpy, pandas
    • scikit-learn, linear regression etc.
    • pytorch
    • llm


Why blog using Docusaurus and Cloudflare Pages

· 3 min read
Software Engineer

Why I decided to setup a blog using Docusaurus and deploy to Cloudflare Pages instead of using gatsby, netlify, or github pages.

Why use static site generator for blog when you have Medium, Wordpress?

I have used several hosted blog services such as Medium, WordPress, Ghost. These managed platforms do not require any setup and provide better exposure thanks to existing audiences on the platform. The main reason I choose to use static site generator is they allow me to write blog as code in plain markdown, version control the content using git and add style/interactive components (in React) when needed. The managed platforms offer many things out of box but their customization and API is limited e.g. Medium API is no longer supported

Why Docusaurus instead of Gatbsy, Hugo, Jekyll, etc?

GitHub pages offers Jekyll and I am not a fan of Ruby (working at AWS on region build made the feeling even worse). Building Jekyll pages locally is much painful compared with Go or NodeJS based static site generator because I don't setup Ruby toolchain on my own devices.

Hugo is in Go but the template syntax and the extensibility is not as good as these React based ones such as Gatsby and Docusaurus.

Gatsby is the one I planned to start with because it offers a GraphQL API, making building extension and interact with other languages a breeze. However, after looking at its blog template, I found there are several things I need to implement by myself such as tag. I am lazy and want most things out of box with a reasonable default that I customize later.

Then I looked into documentation type of static site generator such as Docusaurus and VuePress. I have used VuePress for awesome-time-series-database, but the VuePress blog plugin's last update time is 9 months ago so I tried Docusaurus. The default docusaurus template support both doc and blog with tags, the blog looks better than gatsby's blog template. So I decided to use Docuasurus.

Why Cloudflare Pages instead of Netlify, GitHub Pages?

GitHub Pages is the most straightforward to setup when source code of blog is hosted on GitHub and I used to use it before I switched to Netlify for PR preview which is not supported by GitHub Pages. However, Netlify's free plan has limit on 100GB bandwidth and then $55 Per 100GB while Cloudflare Pages has no limit on bandwidth.

Cloudflare Pages does have its very special 20,000 files hard limit due to technical limit. But as long as I don't copy node_modules into the build directory, it might take years for me to hit that limit with notes and blogs (116 files right now). btw: You can count the files (including subdirectories) using find . -type f | wc -l per stackoverflow. If I did hit the limit, I could host (part of) the website on other places (e.g. nginx, object store like R2/S3) and use (Cloudflare) CDN to serve the content.

In next post I will talk about the actual steps of creating the blog using Docusaurus and configure Cloudflare Pages with github integration and custom domain.