Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0

### Added

- **`name-desc` and `stars-asc` sort values** — `SortValue` now covers both directions for every field: `'name-desc'` sorts Z-A via `sortByName(projects, 'desc')`, and `'stars-asc'` sorts lowest-stars-first via `sortByStars(projects, 'asc')`. Every existing value keeps its meaning; `'stars'` remains descending, mirroring `'date'`. Fixes [#20].
- **Opt-out flags for auto-generated GitHub links** — `github` and `hybrid` projects accept `useGithubLinkFromRepo` and `useLiveLinkFromRepo` (both default `true`) to suppress the repo-URL `github` link and the repo-homepage `live` link. Explicit `links` in config still win. For the pre-existing `linkOrder`-based `live` suppression, the docs now explain how the two mechanisms interact. Fixes [#24].

### Fixed
Expand Down
28 changes: 28 additions & 0 deletions packages/core/src/lib/__tests__/sortProjects.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,20 @@ describe('sortProjects', () => {
})
})

describe('sort by stars-asc', () => {
it('should call sortByStars with asc order (lowest first)', () => {
const projects = [
createProject({ id: '1', type: 'github', stats: { stars: 100 } }),
createProject({ id: '2', type: 'github', stats: { stars: 500 } }),
createProject({ id: '3', type: 'github', stats: { stars: 250 } }),
]

const result = sortProjects(projects, 'stars-asc')

expect(result.map(p => p.id)).toEqual(['1', '3', '2'])
})
})

describe('sort by name', () => {
it('should call sortByName with asc order and return result', () => {
const projects = [
Expand All @@ -58,6 +72,20 @@ describe('sortProjects', () => {
})
})

describe('sort by name-desc', () => {
it('should call sortByName with desc order (Z-A) and return result', () => {
const projects = [
createProject({ id: '1', name: 'Zebra' }),
createProject({ id: '2', name: 'Alpha' }),
createProject({ id: '3', name: 'Beta' }),
]

const result = sortProjects(projects, 'name-desc')

expect(result.map(p => p.id)).toEqual(['1', '3', '2'])
})
})

describe('sort by date', () => {
it('should call sortByDate with desc order (newest first)', () => {
const projects = [
Expand Down
6 changes: 5 additions & 1 deletion packages/core/src/lib/sortProjects.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ import { sortByStars } from './sortByStars'
import { sortByName } from './sortByName'
import { sortByDate } from './sortByDate'

export type SortValue = 'stars' | 'name' | 'date' | 'date-asc'
export type SortValue = 'stars' | 'stars-asc' | 'name' | 'name-desc' | 'date' | 'date-asc'

export function sortProjects(projects: ProjexProject[], sortValue: SortValue): ProjexProject[] {
if (projects.length === 0) {
Expand All @@ -13,8 +13,12 @@ export function sortProjects(projects: ProjexProject[], sortValue: SortValue): P
switch (sortValue) {
case 'stars':
return sortByStars(projects)
case 'stars-asc':
return sortByStars(projects, 'asc')
case 'name':
return sortByName(projects, 'asc')
case 'name-desc':
return sortByName(projects, 'desc')
case 'date':
return sortByDate(projects, 'desc')
case 'date-asc':
Expand Down
28 changes: 26 additions & 2 deletions packages/docs/src/api/types/sort-value.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,15 +5,17 @@ Allowed sort values for the `sortProjects` function. Defines how projects can be
## Definition

```tsx
type SortValue = 'stars' | 'name' | 'date' | 'date-asc'
type SortValue = 'stars' | 'stars-asc' | 'name' | 'name-desc' | 'date' | 'date-asc'
```

## Values

| Value | Description | Direction | Usage |
|-------|-------------|-----------|--------|
| `stars` | Sort by GitHub stars | Descending (highest first) | GitHub and hybrid projects |
| `stars-asc` | Sort by GitHub stars | Ascending (lowest first) | GitHub and hybrid projects |
| `name` | Sort alphabetically by project name | Ascending (A-Z) | All project types |
| `name-desc` | Sort alphabetically by project name | Descending (Z-A) | All project types |
| `date` | Sort by `updatedAt` or `createdAt` | Descending (newest first) | All project types |
| `date-asc` | Sort by `updatedAt` or `createdAt` | Ascending (oldest first) | All project types |

Expand Down Expand Up @@ -41,6 +43,17 @@ const sorted = sortProjects(projects, 'stars')
// [1000 stars, 500 stars, 200 stars, 0 stars, manual project, npm project]
```

### `stars-asc`

- Same data source as `stars`
- Sorts ascending (lowest stars first)
- Projects without stars are still placed at the end

```tsx
const sorted = sortProjects(projects, 'stars-asc')
// [200 stars, 500 stars, 1000 stars, 0 stars, manual project, npm project]
```

### `name`

- Alphabetical sort using `localeCompare` with `sensitivity: 'base'` (case-insensitive)
Expand All @@ -53,6 +66,17 @@ const sorted = sortProjects(projects, 'name')
// ['Alpha Project', 'Beta App', 'Gamma Tool']
```

### `name-desc`

- Same data source as `name`
- Sorts descending (Z-A)
- Projects without a name are still placed at the end

```tsx
const sorted = sortProjects(projects, 'name-desc')
// ['Gamma Tool', 'Beta App', 'Alpha Project']
```

### `date`

- Uses `updatedAt` if available, falls back to `createdAt`
Expand Down Expand Up @@ -93,7 +117,7 @@ function ProjectsPage({ projects }) {
return (
<div>
<ProjectSort
options={['stars', 'name', 'date', 'date-asc']}
options={['stars', 'stars-asc', 'name', 'name-desc', 'date', 'date-asc']}
value={sortBy}
onChange={setSortBy}
/>
Expand Down
10 changes: 6 additions & 4 deletions packages/docs/src/api/utilities/sort-projects.md
Original file line number Diff line number Diff line change
Expand Up @@ -24,12 +24,14 @@ function sortProjects(projects: ProjexProject[], sortValue: SortValue): ProjexPr
| Value | Description |
|-------|-------------|
| `'stars'` | Sort by GitHub stars (descending) |
| `'name'` | Sort alphabetically by name (ascending) |
| `'stars-asc'` | Sort by GitHub stars (ascending) |
| `'name'` | Sort alphabetically by name (ascending, A-Z) |
| `'name-desc'` | Sort alphabetically by name (descending, Z-A) |
| `'date'` | Sort by date (newest first, descending) |
| `'date-asc'` | Sort by date (oldest first, ascending) |

```tsx
type SortValue = 'stars' | 'name' | 'date' | 'date-asc'
type SortValue = 'stars' | 'stars-asc' | 'name' | 'name-desc' | 'date' | 'date-asc'
```

## Behavior
Expand All @@ -43,7 +45,7 @@ type SortValue = 'stars' | 'name' | 'date' | 'date-asc'
```tsx
import { sortProjects, ProjectSort, ProjectGrid, ProjectCard } from '@manningworks/projex'

const SORT_OPTIONS = ['stars', 'name', 'date', 'date-asc']
const SORT_OPTIONS = ['stars', 'stars-asc', 'name', 'name-desc', 'date', 'date-asc']

function ProjectShowcase({ projects }) {
const [sortValue, setSortValue] = useState('stars')
Expand Down Expand Up @@ -81,7 +83,7 @@ import {
} from '@manningworks/projex'

const AVAILABLE_TAGS = ['React', 'TypeScript', 'Node.js']
const SORT_OPTIONS = ['stars', 'name', 'date', 'date-asc']
const SORT_OPTIONS = ['stars', 'stars-asc', 'name', 'name-desc', 'date', 'date-asc']

function ProjectShowcase({ projects }) {
const [query, setQuery] = useState('')
Expand Down