An open API service indexing awesome lists of open source software.

https://github.com/stevemckinney/iamsteve

Design and code blog built with Next.js
https://github.com/stevemckinney/iamsteve

css design ui

Last synced: 2 months ago
JSON representation

Design and code blog built with Next.js

Awesome Lists containing this project

README

          

![iamsteve.me banner](/app/opengraph-image.png)

# iamsteve.me design & code blog

A design and code blog using Next.js with App Router.

## Quick start

Development setup

First, run the development server:

```bash
pnpm build
# or
pnpm dev
```

Open [http://localhost:3000](http://localhost:3000) with your browser to see the result.

## Creating posts

How to create and manage blog posts

### Starting a new post

1. Create a new branch:

```bash
git checkout -b post/your-post-name
```

2. Generate the post:

```bash
node ./scripts/compose.js
```

3. Follow the prompts for:
- Post title
- File extension (md or mdx)
- Post status (open, draft, closed)

### Post structure

Posts can be created in two formats:

1. Single file:

```
content/blog/0177-your-post-title.mdx
```

2. Directory with index file (for posts with assets):

```
content/blog/0177-your-post-title/
├─ index.mdx
├─ image.png
└─ other-assets/
```

### Post id system

- IDs are automatically managed:
- `compose.js` scans existing posts to assign the next available ID
- GitHub Actions handle ID conflicts during pull requests
- Pre-merge-commit hook ensures ID uniqueness when merging

### Publishing workflow

1. Create your post on a new branch
2. Make your changes and commit
3. Create a pull request
4. The system will automatically:
- Check for ID conflicts
- Update IDs if needed
- Handle merging safely

## Post configuration

Frontmatter and image requirements

Example frontmatter:

```yaml
---
title: 'Visual design tips you can apply immediately'
date: '2017-07-04T11:51:00+00:00'
lastmod: '2019-10-04T07:24:49+00:00'
summary: 'Add a little extra polish to any of your designs with these tips.'
metadesc: 'When designing there are things you can rely upon regardless of the situation.'
theme: '#fff7e0'
tags: ['Design']
categories: ['Design']
images: ['/images/blog/visual-design-tips-featured-image.png']
large: '/images/blog/visual-design-tips-featured-image.png'
medium: '/images/blog/visual-design-tips-featured-image-medium.png'
ogImage: '/opengraph-image.png'
status: 'open'
id: 164
fileroot: 'visual-design-tips-you-can-apply-immediately'
---
```

### Field descriptions

- `large`: Main image (592x368 SVG)
- `medium`: Medium image (384x240 SVG)
- `ogImage`: Custom post opengraph image (optional)
- `status`: Post status (open, draft, closed)
- `id`: Unique post identifier (managed automatically)
- `fileroot`: Slug used for image naming
- `images`: Legacy field (not in use)

Collections
The collections script helps manage design and development resource links. It supports both individual entries and bulk imports.

### Adding individual collections

Run the script without arguments for interactive mode:

```bash
node scripts/compose-collection.js
```

You'll be prompted for:

- Title: Name of the resource
- URL: Web address
- Collection: Category (e.g., Inspiration, Typography, UX Design)
- Kind: Type of resource (website, article, resource, or tool)
- Extension: File format (md or mdx)

Example output:

```bash
Title: Awesome Design System
URL: https://design-system-example.com
Collection: Inspiration
Kind: website
Extension: md
Collection item generated successfully at content/collections/design-system-example.md
Updated .last-collection-import to 2025-12-06
```

### Bulk import

To import multiple items, create a JSON file with your collections and pass it to the script:

```bash
node scripts/compose-collection.js bookmarks.json
```

JSON file structure:

```json
[
{
"title": "Example Site",
"url": "https://example.com",
"collection": "Inspiration",
"kind": "website",
"extension": "md"
}
]
```

Example output:

```bash
Created: example
Created: another-example

Updated .last-collection-import to 2025-12-06

Import complete: 2 items processed
```

#### Fields:

- `title`: Resource name (required)
- `url`: Web address (required)
- `collection`: Category name (required) - case-insensitive, automatically normalized (e.g., "inspiration", "Foundry", "UX design", "ux-design" all work)
- `kind`: Type of resource (optional, defaults to 'website')
- Options: website, article, resource, tool
- `extension`: File format (optional, defaults to 'md')
- Options: md, mdx

#### Available collections:

The script automatically normalizes collection names, so you can use any casing:

- **Accessibility** - accessibility standards and guidelines
- **CSS** - CSS resources and tools
- **Code** - code tools and libraries
- **Colour** (or Color) - color theory and tools
- **Content** - content strategy resources
- **Favourites** (or Favorites) - personal favorites
- **Foundry** - type foundries (foundry)
- **Inspiration** - design inspiration galleries (inspiration, etc.)
- **Motion** - motion design resources
- **Publication** - design publications
- **Resource** - general design resources
- **Typography** - typography resources that aren't foundries (typography, etc.)
- **UX design** - UX/UI design resources (ux design, ux-design, uxdesign all work)

The script automatically:

- Generates unique filenames from URLs
- Prevents duplicate entries
- Creates properly formatted markdown files with quoted titles
- Adds timestamps
- Updates `.last-collection-import` tracking file

### "New" badge behavior

Collection items display a "New" badge based on:

- Items added after the last import date (tracked in `.last-collection-import`)
- OR items added within the last 3 months (whichever is more recent)
- The badge automatically disappears on the next import or after 3 months

This ensures newly imported items are highlighted until you perform another import or they become older than 3 months.

## Releases and versioning

How releases are created automatically

### How it works

When a PR is merged to `main`, the release action automatically:

1. Finds the latest git tag (e.g. `v9.0.0`)
2. Checks if there are meaningful changes since that tag
3. Determines the version bump type from commit messages
4. Tags the merge commit directly (no extra commit pushed to `main`)
5. Creates a GitHub release with grouped release notes

This means **one merge = one Vercel build**, not two.

### Version bump rules

**Patch** (automatic — the default, e.g. `v9.0.0` → `v9.0.1`):
Most merges create a patch release. Bug fixes, content updates, design tweaks, and chores all fall into this category.

**Minor** (automatic for features, e.g. `v9.0.0` → `v9.1.0`):
Triggered when commit messages or branch names include `feat:`, `feat/`, or `feature/`:

```
feat: add search to blog
feat(collections): filter by tag
```

Or use a branch name like `feat/search` or `feature/dark-mode`.

**Major** (manual only, e.g. `v9.0.0` → `v10.0.0`):
Major versions are reserved for significant milestones like a full redesign or framework migration. To create one, trigger the release workflow manually from the Actions tab and select "major" as the bump type.

### Release note categories

Release notes are grouped by PR labels (configured in `.github/release.yml`):

- **New features** — `feature`, `enhancement`
- **Bug fixes** — `bug`, `fix`
- **Design** — `design`
- **Content** — `content`
- **Other changes** — everything else

PRs labelled `skip-changelog` and commits from `github-actions[bot]` are excluded.

### Checking out a past version

Every release is tagged, so you can check out any version:

```bash
git checkout v8.2.0
```

## Credits

Acknowledgements

The codebase started from the excellent [tailwind-nextjs-starter-blog](https://github.com/timlrx/tailwind-nextjs-starter-blog) and has since evolved from that.