Remove blog for reviewing purposes

This commit is contained in:
Filip Sodić 2025-02-18 17:01:42 +01:00
parent 9ccb7c28ad
commit e0dac1c93b
29 changed files with 0 additions and 9849 deletions

View File

@ -1,24 +0,0 @@
# build output
dist/
# generated types
.astro/
# deployment
.netlify/
# dependencies
node_modules/
# logs
npm-debug.log*
yarn-debug.log*
yarn-error.log*
pnpm-debug.log*
# environment variables
.env
.env.production
# macOS-specific files
.DS_Store

View File

@ -1,4 +0,0 @@
{
"recommendations": ["astro-build.astro-vscode"],
"unwantedRecommendations": []
}

View File

@ -1,11 +0,0 @@
{
"version": "0.2.0",
"configurations": [
{
"command": "./node_modules/.bin/astro dev",
"name": "Development server",
"request": "launch",
"type": "node-terminal"
}
]
}

View File

@ -1,53 +0,0 @@
# Starlight Starter Kit: Basics
[![Built with Starlight](https://astro.badg.es/v2/built-with-starlight/tiny.svg)](https://starlight.astro.build)
```
npm create astro@latest -- --template starlight
```
[![Open in StackBlitz](https://developer.stackblitz.com/img/open_in_stackblitz.svg)](https://stackblitz.com/github/withastro/starlight/tree/main/examples/basics)
[![Open with CodeSandbox](https://assets.codesandbox.io/github/button-edit-lime.svg)](https://codesandbox.io/p/sandbox/github/withastro/starlight/tree/main/examples/basics)
> 🧑‍🚀 **Seasoned astronaut?** Delete this file. Have fun!
## 🚀 Project Structure
Inside of your Astro + Starlight project, you'll see the following folders and files:
```
.
├── public/
├── src/
│ ├── assets/
│ ├── content/
│ │ ├── docs/
│ │ └── 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.
Images can be added to `src/assets/` and embedded in Markdown with a relative link.
Static assets, like favicons, can be placed in the `public/` directory.
## 🧞 Commands
All commands are run from the root of the project, from a terminal:
| Command | Action |
| :------------------------ | :----------------------------------------------- |
| `npm install` | Installs dependencies |
| `npm run dev` | Starts local dev server at `localhost:4321` |
| `npm run build` | Build your production site to `./dist/` |
| `npm run preview` | Preview your build locally, before deploying |
| `npm run astro ...` | Run CLI commands like `astro add`, `astro check` |
| `npm run astro -- --help` | Get help using the Astro CLI |
## 👀 Want to learn more?
Check out [Starlights docs](https://starlight.astro.build/), read [the Astro documentation](https://docs.astro.build), or jump into the [Astro Discord server](https://astro.build/chat).

View File

@ -1,90 +0,0 @@
import { defineConfig } from 'astro/config';
import starlight from '@astrojs/starlight';
import starlightBlog from 'starlight-blog';
import tailwind from '@astrojs/tailwind';
// https://astro.build/config
export default defineConfig({
site: 'https://your-site.com',
trailingSlash: 'always',
integrations: [
starlight({
title: 'Your SaaS',
customCss: ['./src/styles/tailwind.css'],
description: 'Documentation for your SaaS.',
logo: {
src: '/src/assets/logo.webp',
alt: 'Your SaaS',
},
head: [
// Add your script tags here. Below is an example for Google analytics, etc.
{
tag: 'script',
attrs: {
src: 'https://www.googletagmanager.com/gtag/js?id=<YOUR-GOOGLE-ANALYTICS-ID>',
},
},
{
tag: 'script',
content: `
window.dataLayer = window.dataLayer || [];
function gtag(){dataLayer.push(arguments);}
gtag('js', new Date());
gtag('config', '<YOUR-GOOGLE-ANALYTICS-ID>');
`,
},
],
editLink: {
baseUrl: 'https://github.com/<your-repo>',
},
components: {
SiteTitle: './src/components/MyHeader.astro',
ThemeSelect: './src/components/MyThemeSelect.astro',
Head: './src/components/HeadWithOGImage.astro',
PageTitle: './src/components/TitleWithBannerImage.astro',
},
social: {
github: 'https://github.com/wasp-lang/open-saas',
twitter: 'https://twitter.com/wasplang',
discord: 'https://discord.gg/aCamt5wCpS',
},
sidebar: [
{
label: 'Start Here',
items: [
{
label: 'Introduction',
link: '/',
},
],
},
{
label: 'Guides',
items: [
{
label: 'Example Guide',
link: '/guides/example/',
},
],
},
],
plugins: [
starlightBlog({
title: 'Blog',
customCss: ['./src/styles/tailwind.css'],
authors: {
Dev: {
name: 'Dev',
title: 'Dev @ Your SaaS',
picture: '/CRAIG_ROCK.png', // Images in the `public` directory are supported.
url: 'https://your-site.com',
},
},
}),
],
}),
tailwind({ applyBaseStyles: false }),
],
});

File diff suppressed because it is too large Load Diff

View File

@ -1,22 +0,0 @@
{
"name": "blog",
"type": "module",
"version": "0.0.1",
"scripts": {
"dev": "astro dev",
"start": "astro dev",
"build": "astro check && astro build",
"preview": "astro preview",
"astro": "astro"
},
"dependencies": {
"@astrojs/check": "^0.9.4",
"@astrojs/starlight": "^0.29.2",
"@astrojs/starlight-tailwind": "^2.0.3",
"@astrojs/tailwind": "^5.1.2",
"astro": "^4.16.15",
"sharp": "^0.32.5",
"starlight-blog": "^0.15.0",
"typescript": "^5.4.5"
}
}

View File

@ -1 +0,0 @@
module.exports = {};

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.8 MiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 63 KiB

View File

@ -1,14 +0,0 @@
# OG Images & Banner Images
When images are stored in this directory, they are automatically used as Open Graph (social media preview) Images and Cover/Banner Images for each blog post.
Images stored here must follow the naming convention `<post-slug>.webp` and must always be .webp files, e.g. `2023-11-21-coverlettergpt.webp`.
This is because OG Image URLs and Banner Images are automatically generated for each blog post based on the logic in the custom Title and Head components, e.g. `src/components/HeadWithOGImage.astro`:
```tsx
const ogImageUrl = new URL(
`/banner-images/${Astro.props.id.replace(/blog\//, '').replace(/\.\w+$/, '.webp')}`,
Astro.site,
)
```

Binary file not shown.

Before

Width:  |  Height:  |  Size: 145 KiB

File diff suppressed because one or more lines are too long

Before

Width:  |  Height:  |  Size: 14 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 13 KiB

View File

@ -1,29 +0,0 @@
---
import type { Props } from '@astrojs/starlight/props'
import Default from '@astrojs/starlight/components/Head.astro'
import { BANNER_PATH, DEFAULT_BANNER_IMAGE, getBannerImageFilename, checkBannerImageExists } from './imagePaths'
const bannerImageFileName = getBannerImageFilename({ path: Astro.props.id })
const imageExists = checkBannerImageExists({ bannerImageFileName })
// Get the URL of the social media preview image for the current post using its
// slug ('Astro.props.id') and replace the path and file extension with `.webp`.
let ogImageUrl = new URL(
`${BANNER_PATH}/${DEFAULT_BANNER_IMAGE}`,
Astro.site,
);
if (imageExists) {
ogImageUrl = new URL(
`${BANNER_PATH}/${bannerImageFileName}`,
Astro.site,
)
}
---
<Default {...Astro.props}><slot /></Default>
<!-- Open Graph images. -->
<meta property="og:image" content={ogImageUrl} />
<meta property="og:image:width" content="1200" />
<meta property="og:image:height" content="630" />
<meta name="twitter:image" content={ogImageUrl} />

View File

@ -1,90 +0,0 @@
---
import { logos } from 'virtual:starlight/user-images';
import config from 'virtual:starlight/user-config';
import blogConfig from 'virtual:starlight-blog-config'
import type { Props } from '@astrojs/starlight/props';
const href = Astro.site
const { siteTitle } = Astro.props;
---
<a {href} class="site-title sl-flex">
{
config.logo && logos.dark && (
<>
<img
class:list={{ 'light:sl-hidden': !('src' in config.logo) }}
alt={config.logo.alt}
src={logos.dark.src}
width={logos.dark.width}
height={logos.dark.height}
/>
{/* Show light alternate if a user configure both light and dark logos. */}
{!('src' in config.logo) && (
<img
class="dark:sl-hidden"
alt={config.logo.alt}
src={logos.light?.src}
width={logos.light?.width}
height={logos.light?.height}
/>
)}
</>
)
}
<span class:list={{ 'sr-only': config.logo?.replacesTitle }} class="dark:text-white hover:text-yellow-500">
{siteTitle}
</span>
</a>
<div>
<a href="/" class="text-gray-900 hover:text-yellow-500 dark:text-white">Docs</a>
</div>
<div>
<a href="/blog/" class="text-gray-900 hover:text-yellow-500 dark:text-white">{blogConfig.title}</a>
</div>
<style>
.site-title {
justify-self: flex-start;
max-width: 100%;
overflow: hidden;
align-items: center;
color: var(--sl-color-gray-9);
gap: var(--sl-nav-gap);
font-size: var(--sl-text-h4);
font-weight: 600;
text-decoration: none;
white-space: nowrap;
padding-inline-end: 1rem;
border-inline-end: 1px solid var(--sl-color-gray-5);
}
img {
height: calc(var(--sl-nav-height) - 2 * var(--sl-nav-pad-y));
width: auto;
max-width: 100%;
object-fit: contain;
object-position: 0 50%;
}
div {
border-inline-end: 1px solid var(--sl-color-gray-5);
margin-left: 1rem;
align-self: center;
gap: 1rem;
height: 100%;
padding-inline-end: 1rem;
}
@media (min-width: 50rem) {
div {
align-items: center;
display: flex;
}
}
a {
color: var(--sl-color-text-accent);
font-weight: 600;
text-decoration: none;
}
a:hover {
opacity: 0.66;
}
</style>

View File

@ -1,28 +0,0 @@
---
import StarlightThemeSelect from '@astrojs/starlight/components/ThemeSelect.astro'
import type { Props } from '@astrojs/starlight/props'
---
<StarlightThemeSelect {...Astro.props}>
<slot />
</StarlightThemeSelect>
<style>
div {
border-inline-end: 1px solid var(--sl-color-gray-5);
display: none;
padding-inline-end: 1rem;
}
@media (min-width: 50rem) {
div {
display: flex;
}
}
a {
color: var(--sl-color-text-accent);
font-weight: 600;
text-decoration: none;
}
</style>

View File

@ -1,45 +0,0 @@
---
import type { Props } from '@astrojs/starlight/props'
import { Image } from 'astro:assets';
import { BANNER_PATH, getBannerImageFilename, checkBannerImageExists } from './imagePaths'
const { id, entry } = Astro.props;
const { title, subtitle, hideBannerImage } = entry.data;
const bannerImageFileName = getBannerImageFilename({ path: id })
const imageExists = checkBannerImageExists({ bannerImageFileName })
---
<h1 id='_top'>{title}</h1>
{subtitle && <p class="subtitle">{subtitle}</p>}
{imageExists && <div class="image-container">
<Image src={`${BANNER_PATH}/${bannerImageFileName}`} loading="eager" alt={title} width="50" height="50" class={!hideBannerImage ? 'cover-image' : 'hidden'} />
</div>}
<style>
.image-container {
width: 100%;
max-width: 800px;
margin: 1rem 0;
}
.subtitle {
font-size: var(--sl-text-h4);
color: var(--sl-color-gray-2);
margin: 0.5rem 0;
}
.cover-image {
width: 100%;
height: auto;
border-radius: 8px;
display: block;
}
h1 {
margin: 1rem 0;
font-size: var(--sl-text-h1);
line-height: var(--sl-line-height-headings);
font-weight: 600;
color: var(--sl-color-white);
}
</style>

View File

@ -1,16 +0,0 @@
import path from 'path';
import { existsSync } from 'fs';
import { fileURLToPath } from 'url';
export const BANNER_PATH = '/banner-images';
export const DEFAULT_BANNER_IMAGE = 'default-banner.webp';
export const getBannerImageFilename = ({ path }: { path: string }) =>
path.replace(/.*\//, '').replace(/\.\w+$/, '.webp');
export const checkBannerImageExists = ({ bannerImageFileName }: { bannerImageFileName: string }) => {
const __dirname = path.dirname(fileURLToPath(import.meta.url));
const imagePath = path.join(__dirname, `../../public/${BANNER_PATH}`, bannerImageFileName);
return existsSync(imagePath);
};

View File

@ -1,20 +0,0 @@
import { defineCollection } from 'astro:content';
import { i18nSchema, docsSchema } from '@astrojs/starlight/schema';
import { blogSchema } from 'starlight-blog/schema';
import { z } from 'astro:content';
export const collections = {
docs: defineCollection({
schema: docsSchema({
extend: (context) => {
const blogSchemaResult = blogSchema(context);
return z.object({
...blogSchemaResult.shape,
subtitle: z.string().optional(),
hideBannerImage: z.boolean().optional(),
});
},
}),
}),
i18n: defineCollection({ type: 'data', schema: i18nSchema() }),
};

View File

@ -1,157 +0,0 @@
---
title: How I Built & Grew CoverLetterGPT to 5,000 Users and $200 MRR
date: 2023-11-21
tags: ["indiehacker", "saas", "sideproject"]
subtitle: A guide to building a profitable, open-source side-project
hideBannerImage: false # Banner images stored in public/banner-images/ are automatically used as cover images and social media preview images (og:image) for each blog post.
authors:
- name: vince
title: Dev Rel @ Wasp
url: https://wasp.sh
---
## Hey, Im Vince…
![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/az8xf61b2qxx1msfo4t5.png)
Im a self-taught developer that changed careers during the Covid Pandemic. I did it because I wanted a better career, enjoyed programming, and at the same time, had a keen interest in IndieHacking.
<!--truncate-->
If youre not aware, IndieHacking is the movement of developers who build potentially profitable side-projects in their spare time. And there are some very successful examples of IndieHackers and “solopreneurs” out there inspiring others, such as [levels.io](http://levels.io) and [Marc Lou](https://twitter.com/marc_louvion).
This thought of being able to build my own side-project that could generate profit while I slept was always attractive to me.
![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/e1r07ajn3gysdscjdkns.png)
So Im happy to report that Ive finally done it with my first software-as-a-service (SaaS) app, [CoverLetterGPT.xyz](http://CoverLetterGPT.xyz), which I launched in March 2023!
Ill be the first to admit that the results arent spectacular, but theyre still something Im very proud of:
- over 5,000 registered users
- $203 monthly recurring revenue (MRR)
Below, Im going to share with you how I built it (yes, its [open-source](https://github.com/vincanger/coverlettergpt)!), how I marketed and monetized it, along with a bunch of helpful resources to help you build your own profitable side-project.
## What the heck is CoverLetterGPT?
[CoverLetterGPT.xyz](http://CoverLetterGPT.xyz) was an idea I got after the OpenAI API was released. Its an app that allows you to upload a PDF of your CV/resumé, along with the job description youre applying to, and it will generate and edit unique cover letters for you based on this information.
{% embed https://youtu.be/ZhcFRD9cVrI %}
It also lets you save and manage your cover letters per each job, making it easy to make and apply to multiple jobs without having to keep copy and pasting all your important info into ChatGPT!
## Whats the Tech Stack?
![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/xpb97bgrx98bwxemrg0o.png)
CoverLetterGPT is entirely open-source, so you can [check out the code](https://github.com/vincanger/coverlettergpt), fork it, learn from it, make your own, submit a PR (Id love you forever if you did 🙂)… whatever!
I built it using the [Wasp full-stack framework](https://wasp.sh) which allowed me to ship it about 10x faster.
Why?
Because [Wasp](https://wasp.sh) as a framework allows you to describe your apps core features in a `main.wasp` config file. Then it continually compiles and “glues” these features into a React-ExpressJS-Prisma full-stack app for you.
All you have to focus on is writing the client and server-side logic, and Wasp will do the boring stuff for you, like authentication & authorization, server config, email sending, and cron jobs.
BTW, [Wasp](https://wasp.sh) is open-source and free and you can help the project out a ton by starring the repo on GitHub: [https://www.github.com/wasp-lang/wasp](https://www.github.com/wasp-lang/wasp) 🙏
![https://media1.giphy.com/media/ZfK4cXKJTTay1Ava29/giphy.gif?cid=7941fdc6pmqo30ll0e4rzdiisbtagx97sx5t0znx4lk0auju&ep=v1_gifs_search&rid=giphy.gif&ct=g](https://media1.giphy.com/media/ZfK4cXKJTTay1Ava29/giphy.gif?cid=7941fdc6pmqo30ll0e4rzdiisbtagx97sx5t0znx4lk0auju&ep=v1_gifs_search&rid=giphy.gif&ct=g)
{% cta [https://www.github.com/wasp-lang/wasp](https://www.github.com/wasp-lang/wasp) %} ⭐️ Thanks For Your Support 🙏 {% endcta %}
For the UI, I used [Chakra UI](https://chakra-ui.com/), as I always do. I like that its a component-based UI library. This helps me build UIs a lot faster than I would with Tailwind or vanilla CSS.
For payments, I used [Stripe](https://www.notion.so/How-I-Built-and-Open-Sourced-CoverLetterGPT-5-000-users-200-MRR-0d32f13fa00a440fb8e08c8dbf2b8a27?pvs=21), (Ill go into the details of monetization below).
The Server and Postgres Database are hosted on [https://railway.app](https://railway.app/), with the client on [Netlify.com](http://Netlify.com)s free tier.
![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/09ca1yaqodkb7b2vnwr9.png)
By the way, If youre interested in building your own SaaS with almost the same stack as above, I also built a [free SaaS template](https://github.com/wasp-lang/SaaS-Template-GPT) you can use that will save you days of work!
## How I Marketed It
My biggest take-away from this whole project was that open-sourcing it was the best way to market it!
This seems counter-intuitive, right? Why would making the code available for anyone to see and copy be good for a business? Youre basically rolling out a red carpet for competitors, arent you?
Well, not quite.
First of all, the number of people who will realistically spend the time and energy launching a direct competitor is low. Also, most people interested in your open-source code want to learn some aspect of it and apply it to their own ideas, not just copy yours directly.
Secondly, and most importantly, the fact that its open-source makes people a lot more receptive to you talking about it.
![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/q79djej6doj2yq10l2og.png)
When you present something youve built and give people the opportunity to learn from it, theyre much more welcoming! As a result, theyre more likely to upvote it, share it, use it, and recommend it to others.
This is exactly what happened with CoverLetterGPT! As a result of me sharing the open-source code, it get featured on the [IndieHackers.com](https://www.indiehackers.com/post/whats-new-don-t-build-things-no-one-wants-833ee752ba?utm_source=indie-hackers-emails&utm_campaign=ih-newsletter&utm_medium=email) newsletter (>100k subscribers), shared on blogs, and talked about on social media platforms.
![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/44rlv65u97qhufbhqt0k.png)
And even though its a small, simple product, I tried launching it on [Product Hunt](http://producthunt.com), where it also performed considerably well.
So, all together, these initial efforts combined gave my product a good initial marketing presence. To this day, I havent really done much else to market it, except some twitter posts (and this post, if you want to consider it marketing 🤑).
## How I Monetized It
When I first launched in March 2023, I didnt really expect anyone to pay for the product, but I wanted to learn how to use Stripe as a payments processor, thinking that the skills might be useful in the future.
So I started simple, and just put a one-time payment link for tips. No paywall, no subscriptions. It was entirely free to use with any tip amount welcome.
To my surprise, tips started coming in, with some as high as $10 dollars!
This encouraged me to force users to login to use the product, and add a paywall after users used up 3 credits.
My initial payment options were:
- $4.95 for a 3 months access
- $2.95 for 10 cover letter generations
![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/golo3tnh3o0sy5sujrer.png)
That went reasonably well until I implemented the ability for users to use GPT to make finer edits to their generated cover letters. Thats when I changed my pricing and thats when better profits started to come in:
- $5.95 / month subscription with GPT-4
- $2.95 / month subscription with GPT-3.5-turbo
Currently, over 90% of my customers choose the more powerful, more [expensive plan with GPT-4](https://openai.com/pricing), even though the 3 trial credits use the GPT-3.5-turbo model.
(I also integrated Bitcoin Lightning payments — check out the [repo](https://github.com/vincanger/coverlettergpt) if you want to learn how — but havent received any yet.)
Now, with an MRR of ~$203, my monthly profit of course depends on my costs, which are:
- Domain Name: $10/year
- OpenAI bill: ~ $15/month
- Hosting bill: ~ $3/month
Which leaves me at about ~ $183/month in profits 😀
## Future Plans
One of the most surprising aspects about [CoverLetterGPT.xyz](http://CoverLetterGPT.xyz)s success is that, on the surface, the product is very simple. Also, Ive done very little in the way of SEO marketing, and havent continued to market it much at all. The current growth is mostly organic at this point thanks to my initial marketing efforts.
But I still have some plans to make it better:
- buy a better top-level domain (TLD), like [CoverLetterGPT.ai](http://CoverLetterGPT.ai)
- add more features, like the ability to generate interview questions based on the cover letters
- improve the UX and make it look more “professional”
If you have any other ideas how I could improve it, drop me a comment, message me on [twitter/x](https://twitter.com/hot_town), or submit a [PR to the repo](https://github.com/vincanger/coverlettergpt).
## Final Words + More Resources
My intention with this article was to help others who might be considering launching their own SaaS product. So I hope thats been the case here. If you still have any questions, dont hesitate to ask.
Here are also the most important links from this article along with some further resources that will help in building and marketing your own profitable side-project:
- 👨‍💻 [CoverLetterGPT GitHub Repo](https://github.com/vincanger/coverlettergpt)
- 💸 [Free Full-Stack SaaS Template w/ Google Auth, Stripe, GPT, & instructions in the README!](https://github.com/wasp-lang/SaaS-Template-GPT)
- ✍️ [Initial CoverLetterGPT Reddit Post](https://www.reddit.com/r/webdev/comments/11uh4qo/comment/jco5ggp/?utm_source=share&utm_medium=web2x&context=3)
- 🪓 [IndieHackers Feature](https://www.indiehackers.com/post/whats-new-don-t-build-things-no-one-wants-833ee752ba?utm_source=indie-hackers-emails&utm_campaign=ih-newsletter&utm_medium=email)
- 💸 [Great Video on how to use Stripe CLI & Webhooks](https://www.youtube.com/watch?v=Psq5N5C-FGo&t=1041s)
Oh, and if you found these resources useful, don't forget to support Wasp by [starring the repo on GitHub](https://github.com/wasp-lang/wasp)!
![https://res.cloudinary.com/practicaldev/image/fetch/s--OCpry2p9--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_66%2Cw_800/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/bky8z46ii7ayejprrqw3.gif](https://res.cloudinary.com/practicaldev/image/fetch/s--OCpry2p9--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_66%2Cw_800/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/bky8z46ii7ayejprrqw3.gif)
{% cta [https://www.github.com/wasp-lang/wasp](https://www.github.com/wasp-lang/wasp) %} ⭐️ Thanks For Your Support 🙏 {% endcta %}

View File

@ -1,12 +0,0 @@
---
title: My first blog post
date: 2023-11-20
tags: ["blog", "post", "saas", "rocknroll"]
authors: ["Dev"]
---
## Hello
Hello world!
![rock n roll baby](/CRAIG_ROCK.png)

View File

@ -1,9 +0,0 @@
---
title: Example Guide
---
This is an example guide. It's a good idea to have a guide for each major feature of your project. Guides should be short and to the point. They should also be written in a way that is easy to understand for beginners.
## Example Heading
...

View File

@ -1,5 +0,0 @@
---
title: Introduction
---
Hello World! 👋

View File

@ -1,2 +0,0 @@
/// <reference path="../.astro/types.d.ts" />
/// <reference types="astro/client" />

View File

@ -1,3 +0,0 @@
@tailwind base;
@tailwind components;
@tailwind utilities;

View File

@ -1,22 +0,0 @@
declare module 'virtual:starlight-blog-config' {
const StarlightBlogConfig: import('./libs/config').StarlightBlogConfig;
export default StarlightBlogConfig;
}
declare module 'virtual:starlight/user-config' {
const Config: import('@astrojs/starlight/types').StarlightConfig;
export default Config;
}
declare module 'virtual:starlight/user-images' {
type ImageMetadata = import('astro').ImageMetadata;
export const logos: {
dark?: ImageMetadata;
light?: ImageMetadata;
};
}
declare module 'virtual:astro-config' {
const Config: import('@astrojs/types').Config;
export default Config;
}

View File

@ -1,18 +0,0 @@
import starlightPlugin from "@astrojs/starlight-tailwind";
import colors from "tailwindcss/colors";
const yellow = colors.yellow
const gray = colors.gray
/** @type {import('tailwindcss').Config} */
export default {
content: ["./src/**/*.{astro,html,js,jsx,md,mdx,svelte,ts,tsx,vue}"],
theme: {
extend: {
colors: {
accent: yellow, gray
},
},
},
plugins: [starlightPlugin()],
};

View File

@ -1,3 +0,0 @@
{
"extends": "astro/tsconfigs/strict",
}