Files
open-saas/opensaas-sh/blog
Fran 2caac6c1de OpenSaaS Redesign - Add ShadCN, and redesign OpenSaaS.sh landing page (#447)
* add shadcn and shadcn script

* cleanup

* navbar and announcement

* remove unnecessary documentation

* cleanup

* dark mode switcher

* update hero

* update features

* update clients

* update testimonials

* update faq

* add avatar and use it in hero

* update the demo app

* update pricing page

* update file upload page

* update account page

* update dropdown

* fix mobile menu

* use card for testimonials

* update analytics to use new color tokens

* use sheet for mobile nav bar

* update user table

* update settings page to use shadcn components

* update testimonials to use new design

* add section title component

* update components to use section header

* add gradients

* add secondary muted

* add dynamic navbar

* cleanup

* fix color tokens for the dark mode

* don't scale all the cards

* Examples component

* fix the carousel scrolling into view

* add highlighted feature component

* add features grid

* cleanup

* fix navbar announcment sticking

* fix padding

* cleanup

* cleanup

* cleanup

* cleanup

* cleanup

* more robust on mouse leave for examples carousel

* auto scroll threshold set to 1

* generate app diff fo creating opensaassh

* add orbit

* fix mobile layout for Hero

* update template FeaturesGrid, and fix logos location

* Update the title for the features grid on landing

* update testimoinals layout

* update contentSections to support new testimonials

* update examples carousel

* update examples carouselui

* cleanup

* fix navbar layout when Announcement not present

* add highlighted features in examples

* cleanup

* fix faq component

* fix testimonials UI

* cleanup

* cleanup

* update contentSections

* update the ui limits

* make highlighted feature items centered

* remove inconsistent styles

* remove legacy classnames

* standardize chart cards

* fix dark mode ui issue with dropdown

* make it so that you can't change your own admin status

* fix changes with filtering on user table

* make filtering more intuitive

* fix calendar visibility issues

* remove forms pages

* use type tel for phone number

* button page redo

* clean up breadrcrumb and remove comments from default layout

* clean up navbar

* throttle scroll for navbar

* clean up remaining template items

* clean up

* fix the examples carousel so that it automatically scrolls

* fix demo app page

* fix FeaturesGrid types

* fix highlighted feature

* fix section title

* Replace old icons

* Remove package-lock.json

* fix opensaas issues

* remove all legacy icons

* remove accidental package files

* update throttleWithTrailingInvocation

* refactor the FeaturesGrid

* clean up highlithted feature

* clean up highlithted feature

* fix behavior of ExamplesCarousel

* clean up ExamplesCarousel

* fix wrong copy and layout on the landing for opensaas.sh

* center examples on the page if there are not enough of them

* Fix layout of pricing

* fix wrong link

* color of sidebar on admin

* add new examples

* fix icon layout

* adds specific tokens for opensaas landing

* layout fix

* remove leftover custom svgs

* update layout to better match figma

* use kebab-case for forms

* revert to h3

* png -> webp

* Update layout for bento grid for opensaas

* parse day views only once

* dropdown edit delete to shadcn

* remove the remaining svgs

* make useDebounce generic

* address small pr comments

* update examples carousel

* remove the banner from the hero

* section title subtitle → description

* remove unnecessary files

* address layout comments for opensaas.sh

* add back git star count

* update contentSections to have currently deployed copy

* useRef instaed of class query

* address layout comments for opensaas.sh

* adjust padding for RepoInfo on diff

* fix gradient on template

* Revert "fix gradient on template"

This reverts commit 4b45f7f437.

* fix gradient on template

* add AI Ready highlighted feature

* update landing page features & add LLM copy button and

Introduced a 'Copy URL for LLMs' button to the blog navbar by creating CopyForLlmButton.astro and integrating it into a new MyRightNavBarItems.astro component, replacing the previous theme select. Updated astro.config.mjs to use the new component. In the app template, added an example highlighted feature component to the landing page and updated testimonial avatars. Also enabled Google, GitHub, Discord, and Slack auth providers in main.wasp.

* Update NavBar announcement for Product Hunt launch

Refactored the Announcement component in NavBar to promote the Open SaaS v2.0 Product Hunt launch, including dynamic messaging based on launch date and updated links. Also updated the landing page to import and render new example components.

---------

Co-authored-by: vincanger <70215737+vincanger@users.noreply.github.com>
2025-07-28 18:29:22 +02:00
..
2025-07-02 12:58:37 +02:00
2025-02-13 12:59:17 +01:00

OpenSaaS Docs and Blog

This is the docs and blog for the OpenSaaS.sh website, Built with Starlight

🚀 Project Structure

Inside of your Astro + Starlight project, you'll see the following folders and files:

.
├── public/
├── src/
│   ├── assets/
│   ├── components/
│   ├── content/
│   │   ├── docs/
│   │   │   ├── blog/
│   │   │   ├── guides/
│   │   │   └── ...
│   │   └── config.ts
│   └── env.d.ts
├── astro.config.mjs
├── package.json
└── tsconfig.json

Starlight looks for .md or .mdx files in the src/content/docs/ directory. Each file is exposed as a route based on its file name.

Blog posts are in the src/content/docs/blog/ directory. Use .mdx files for blog posts.

Images can be added to src/assets/ and embedded in Markdown with a relative link.

Static assets, like favicons and banner images, can be placed in the public/ directory.

We have a number of custom components in src/components/ that you can use in your blog posts and docs.

Custom Components

Custom components in the src/components/ that replace default Starlight components are imported into the astro.config.mjs file:

components: {
  SiteTitle: './src/components/MyHeader.astro',
  ThemeSelect: './src/components/MyThemeSelect.astro',
  Head: './src/components/HeadWithOGImage.astro',
  PageTitle: './src/components/TitleWithBannerImage.astro',
},

Other components can be imported into your blog posts and docs using the import statement:

---
title: "Open SaaS Tutorial"
date: 2024-12-10
//...
---
import VideoPlayer from '../../../components/VideoPlayer.astro';

HeadWithOGImage

This component is used to generate the Open Graph (OG) meta tags for the social media preview images for each doc and blog post.

It checks if a banner image exists in ./public/banner-images with the same name as the blog post but with a .webp extension, e.g. if the blog post is 2024-12-10-open-saas-tutorial.mdx, it checks for ./public/banner-images/2024-12-10-open-saas-tutorial.webp. If it does, it uses that image. If it doesn't, it uses the default banner image.

Generally, the default banner image is used for docs, and blog posts use a custom banner image.

TitleWithBannerImage

This component uses the same image as the HeadWithOGImage component to display a banner image above the title of the blog post.

You can use the hideBannerImage prop to hide the banner image on the page:

---
title: "Open SaaS Tutorial"
date: 2024-12-10
hideBannerImage: true
---

Because the same image in ./public/banner-images is used for social media preview images and the banner image on the doc/blog page, hideBannerImage: true will hide the banner image on the doc/blog page, but still use that image for the social media preview image.

VideoPlayer

This component is a wrapper around the video element that adds some default styles.

You can pass three props to the component:

  • src (required): the path to the video file
  • lgWidth (optional): the width of the video player on large screens greater than 425px. If no prop is passed the default is 55%.
  • smWidth (optional): the width of the video player on small screens less than 425px. If no prop is passed the default is 100%.
---
title: "Open SaaS Tutorial"
date: 2024-12-10
//...
---
import VideoPlayer from '../../../components/VideoPlayer.astro';

<VideoPlayer src="/videos/open-saas-tutorial.mp4" lgWidth="75%" smWidth="80%" />

MyHeader

This component is a wrapper around the Header component from the @astrojs/starlight package.

It repositions the docs and blog links to the left, and adds a logo and a link to the home page, https://opensaas.sh.

Authoring Content

The docs and blog are written in Markdown or MDX with some additional metadata:

title: We Made the Most Annoying Cookie Banners Ever
date: 2024-11-26
tags:
  - cookie consent
  - saas
  - sideproject
  - hackathon
subtitle: and it was totally worth it
hideBannerImage: true
authors: vince

Most posts are written in MDX, which allows you to use jsx components in your blog posts. It's recommended to use the MDX extension for your editor, such as this one for VSCode.

Blog Post Metadata

authors is required and will display the authors of the blog post. To configure a new author, add the proper metadata to astro.config.mjs under plugins > starlightBlog > authors:

authors: {
  vince: {
    name: 'Vince',
    title: 'Dev Rel @ Wasp',
    picture: '/CRAIG_ROCK.png', // Put author images in the `public` directory.
    url: 'https://wasp.sh',
  },
},

subtitle is optional and will display a subtitle below the title of the blog post.

hideBannerImage is optional and will hide the banner image in ./public/banner-images on the blog post page if you only want it to be displayed as the social media preview image (remember, the same image is used for both the social media preview image and the banner image on the blog post page).

Images

Images to be used in guides and posts are stored in ./src/assets and are referenced in the blog posts with a relative path.

Banner images used for social media preview images, as well as cover images for blog posts, are stored in ./public/banner-images and must always use the .webp extension. If a banner image is not found, the default banner image is used. (Note: banner images for docs are used only for social media preview images, where for blog posts the are used as social media preview images and as cover images on the blog post page unless the hideBannerImage metadata is set to true.)

See the HeadWithOGImage and TitleWithBannerImage sections for more information.

Always use astro's Image component to embed images in your blog posts and docs as Astro will automatically optimize the images for the web.

import { Image } from 'astro:assets';
import myImage from '../../../assets/my-image.jpg';

<Image src={myImage} alt="My Image" />

Video

Videos to be used in blog posts are stored in ./src/assets/ and are referenced in the blog posts with a relative path, just like images.

Always use the VideoPlayer component to embed videos in your blog posts. See the VideoPlayer component section for more information.