create-rush-cms 0.1.0 → 0.2.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/package.json +1 -1
- package/template/README.md +28 -7
- package/template/package.json +2 -2
- package/template/src/components/list-page.astro +95 -0
- package/template/src/pages/[...path].astro +2 -0
- package/template/src/views/collection.astro +12 -75
- package/template/src/views/index.ts +5 -1
- package/template/src/views/taxonomy.astro +21 -0
package/package.json
CHANGED
package/template/README.md
CHANGED
|
@@ -52,19 +52,20 @@ no navigation links. See [Routes](https://github.com/rush-cms/js/tree/main/packa
|
|
|
52
52
|
|
|
53
53
|
No page file encodes a URL shape:
|
|
54
54
|
|
|
55
|
-
| File | Answers
|
|
56
|
-
| ------------------------------------- |
|
|
57
|
-
| `src/pages/[...path].astro` | Every homepage,
|
|
58
|
-
| `src/pages/404.astro` | Every other path, on demand: redirects retired slugs, else the not-found page
|
|
59
|
-
| `src/pages/[...locale]/contact.astro` | The contact form of each locale, on demand
|
|
60
|
-
| `src/pages/sitemap.xml.ts` | The sitemap, from the same routes
|
|
61
|
-
| `src/pages/robots.txt.ts` | `robots.txt` (everything disallowed in a preview deployment)
|
|
55
|
+
| File | Answers |
|
|
56
|
+
| ------------------------------------- | -------------------------------------------------------------------------------- |
|
|
57
|
+
| `src/pages/[...path].astro` | Every homepage, list page, taxonomy listing and entry, prerendered at build time |
|
|
58
|
+
| `src/pages/404.astro` | Every other path, on demand: redirects retired slugs, else the not-found page |
|
|
59
|
+
| `src/pages/[...locale]/contact.astro` | The contact form of each locale, on demand |
|
|
60
|
+
| `src/pages/sitemap.xml.ts` | The sitemap, from the same routes |
|
|
61
|
+
| `src/pages/robots.txt.ts` | `robots.txt` (everything disallowed in a preview deployment) |
|
|
62
62
|
|
|
63
63
|
The dispatcher hands each page to a view:
|
|
64
64
|
|
|
65
65
|
- `src/views/home.astro`: the front page of every locale. It is a static welcome page; replace it with your design,
|
|
66
66
|
or render the homepage built in Rush CMS from `page.homepage`.
|
|
67
67
|
- `src/views/collection.astro`: a collection list page with pagination.
|
|
68
|
+
- `src/views/taxonomy.astro`: the entries of a category or tag, with pagination (see [Taxonomies](#taxonomies)).
|
|
68
69
|
- `src/views/entry.astro`: an entry with its title, featured image, excerpt and every rich-text field.
|
|
69
70
|
- `src/views/not-found.astro`: the 404 page.
|
|
70
71
|
|
|
@@ -79,6 +80,26 @@ const views: ViewMap = { posts: { entry: PostEntry } }
|
|
|
79
80
|
A view receives the same props as the generic one (`EntryViewProps` or `ListViewProps`), and `npm run check` fails
|
|
80
81
|
when it does not. `src/astro-modules.d.ts` lets plain TypeScript read the `.astro` imports of that file.
|
|
81
82
|
|
|
83
|
+
## Taxonomies
|
|
84
|
+
|
|
85
|
+
Categories and tags have no pages until `taxonomies` in `astro.config.ts` gives their type a path segment in every
|
|
86
|
+
locale of `localePaths`:
|
|
87
|
+
|
|
88
|
+
```ts
|
|
89
|
+
taxonomies: {
|
|
90
|
+
category: { en: 'category', pt_BR: 'categoria' },
|
|
91
|
+
tag: { en: 'tag', pt_BR: 'tag' }
|
|
92
|
+
}
|
|
93
|
+
```
|
|
94
|
+
|
|
95
|
+
Each category or tag with entries then gets a listing page per locale (`/category/design`, `/pt/categoria/design`,
|
|
96
|
+
`/category/design/page/2`), rendered by `src/views/taxonomy.astro` (`TaxonomyViewProps`) and listed in the sitemap.
|
|
97
|
+
The language switcher and the `hreflang` links of a listing point at the same category or tag in the other locales
|
|
98
|
+
(`page.alternates`). A locale where it has no entries gets no `hreflang` link, and its switcher link goes to its
|
|
99
|
+
homepage.
|
|
100
|
+
Link to one with `getUrls(Astro).taxonomy(tag, locale)`, for instance from an entry's `categories`. See
|
|
101
|
+
[Taxonomies](https://github.com/rush-cms/js/tree/main/packages/astro#taxonomies) for the rules.
|
|
102
|
+
|
|
82
103
|
## Navigation and forms
|
|
83
104
|
|
|
84
105
|
Site content is fetched by stable keys that you create in Rush CMS:
|
package/template/package.json
CHANGED
|
@@ -14,8 +14,8 @@
|
|
|
14
14
|
},
|
|
15
15
|
"dependencies": {
|
|
16
16
|
"@astrojs/node": "11.1.11",
|
|
17
|
-
"@rushcms/astro": "0.
|
|
18
|
-
"@rushcms/client": "4.
|
|
17
|
+
"@rushcms/astro": "0.3.1",
|
|
18
|
+
"@rushcms/client": "4.1.0",
|
|
19
19
|
"@tailwindcss/typography": "0.5.20",
|
|
20
20
|
"@tailwindcss/vite": "4.3.5",
|
|
21
21
|
"astro": "7.4.7",
|
|
@@ -0,0 +1,95 @@
|
|
|
1
|
+
---
|
|
2
|
+
import { getRush, getUrls } from '@rushcms/astro'
|
|
3
|
+
import Hreflang from '@rushcms/astro/components/hreflang.astro'
|
|
4
|
+
import RushImage from '@rushcms/astro/components/rush-image.astro'
|
|
5
|
+
import type { Alternate, Entry, LocaleCode } from '@rushcms/client'
|
|
6
|
+
import Base from '../layouts/base.astro'
|
|
7
|
+
import { formatDate } from '../lib/locale'
|
|
8
|
+
|
|
9
|
+
type PageUrl = (page: number) => string | undefined
|
|
10
|
+
|
|
11
|
+
type Props = {
|
|
12
|
+
locale: LocaleCode
|
|
13
|
+
title: string
|
|
14
|
+
page: number
|
|
15
|
+
lastPage: number
|
|
16
|
+
entries: Entry[]
|
|
17
|
+
pageUrl: PageUrl
|
|
18
|
+
translations?: Alternate[]
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
const { locale, title, page, lastPage, entries, pageUrl, translations = [] } = Astro.props
|
|
22
|
+
const urls = getUrls(Astro)
|
|
23
|
+
const site = await getRush(Astro).site.get()
|
|
24
|
+
const previous = page > 1 ? pageUrl(page - 1) : undefined
|
|
25
|
+
const next = page < lastPage ? pageUrl(page + 1) : undefined
|
|
26
|
+
const current = pageUrl(page)
|
|
27
|
+
const canonical = Astro.site && current !== undefined ? new URL(current, Astro.site) : undefined
|
|
28
|
+
const heading = page > 1 ? `${title} (${page}/${lastPage})` : title
|
|
29
|
+
---
|
|
30
|
+
|
|
31
|
+
<Base locale={locale} title={`${heading} | ${site.name}`} translations={translations}>
|
|
32
|
+
{canonical && <link slot="head" rel="canonical" href={canonical.href} />}
|
|
33
|
+
{page === 1 && <Hreflang slot="head" alternates={translations} />}
|
|
34
|
+
<div class="mx-auto max-w-6xl px-6 py-16">
|
|
35
|
+
<header class="max-w-3xl">
|
|
36
|
+
<h1 class="text-4xl font-semibold tracking-tight">{title}</h1>
|
|
37
|
+
{
|
|
38
|
+
lastPage > 1 && (
|
|
39
|
+
<p class="mt-2 text-muted">
|
|
40
|
+
Page {page} of {lastPage}
|
|
41
|
+
</p>
|
|
42
|
+
)
|
|
43
|
+
}
|
|
44
|
+
</header>
|
|
45
|
+
{
|
|
46
|
+
entries.length > 0 ? (
|
|
47
|
+
<ul class="mt-12 grid gap-6 sm:grid-cols-2 lg:grid-cols-3">
|
|
48
|
+
{entries.map((entry) => (
|
|
49
|
+
<li>
|
|
50
|
+
<article class="card group relative flex h-full flex-col">
|
|
51
|
+
{entry.featured_image?.url && (
|
|
52
|
+
<RushImage
|
|
53
|
+
media={entry.featured_image}
|
|
54
|
+
class="mb-4 aspect-video w-full rounded-lg object-cover"
|
|
55
|
+
/>
|
|
56
|
+
)}
|
|
57
|
+
<h2 class="text-lg font-medium group-hover:text-accent">
|
|
58
|
+
<a href={urls.servedPath(entry, locale)} class="after:absolute after:inset-0">
|
|
59
|
+
{entry.title}
|
|
60
|
+
</a>
|
|
61
|
+
</h2>
|
|
62
|
+
{entry.excerpt && <p class="mt-2 line-clamp-3 text-muted">{entry.excerpt}</p>}
|
|
63
|
+
<p class="mt-auto pt-4 text-sm text-muted">
|
|
64
|
+
<time datetime={entry.published_at}>
|
|
65
|
+
{formatDate(entry.published_at, locale)}
|
|
66
|
+
</time>
|
|
67
|
+
</p>
|
|
68
|
+
</article>
|
|
69
|
+
</li>
|
|
70
|
+
))}
|
|
71
|
+
</ul>
|
|
72
|
+
) : (
|
|
73
|
+
<p class="mt-12 text-muted">Nothing has been published here yet.</p>
|
|
74
|
+
)
|
|
75
|
+
}
|
|
76
|
+
{
|
|
77
|
+
lastPage > 1 && (
|
|
78
|
+
<nav aria-label="Pagination" class="mt-12 flex items-center justify-between gap-4">
|
|
79
|
+
{previous ? (
|
|
80
|
+
<a href={previous} rel="prev" class="button button-secondary">
|
|
81
|
+
Previous page
|
|
82
|
+
</a>
|
|
83
|
+
) : (
|
|
84
|
+
<span />
|
|
85
|
+
)}
|
|
86
|
+
{next && (
|
|
87
|
+
<a href={next} rel="next" class="button button-secondary">
|
|
88
|
+
Next page
|
|
89
|
+
</a>
|
|
90
|
+
)}
|
|
91
|
+
</nav>
|
|
92
|
+
)
|
|
93
|
+
}
|
|
94
|
+
</div>
|
|
95
|
+
</Base>
|
|
@@ -5,6 +5,7 @@ import { routePage } from '../lib/route-page'
|
|
|
5
5
|
import Home from '../views/home.astro'
|
|
6
6
|
import { viewsFor } from '../views/index'
|
|
7
7
|
import NotFound from '../views/not-found.astro'
|
|
8
|
+
import Taxonomy from '../views/taxonomy.astro'
|
|
8
9
|
|
|
9
10
|
export * from '@rushcms/astro/site-paths'
|
|
10
11
|
|
|
@@ -28,5 +29,6 @@ const { list: List, entry: Entry } = viewsFor(collection, getUrls(Astro))
|
|
|
28
29
|
|
|
29
30
|
{page.kind === 'homepage' && <Home page={page} />}
|
|
30
31
|
{page.kind === 'collection' && <List page={page} />}
|
|
32
|
+
{page.kind === 'taxonomy' && <Taxonomy page={page} />}
|
|
31
33
|
{page.kind === 'found' && <Entry entry={page.entry} locale={page.locale} />}
|
|
32
34
|
{page.kind === 'missing' && <NotFound />}
|
|
@@ -1,84 +1,21 @@
|
|
|
1
1
|
---
|
|
2
|
-
import { collectionAlternates,
|
|
3
|
-
import
|
|
4
|
-
import Base from '../layouts/base.astro'
|
|
5
|
-
import { formatDate } from '../lib/locale'
|
|
2
|
+
import { collectionAlternates, getUrls } from '@rushcms/astro'
|
|
3
|
+
import ListPage from '../components/list-page.astro'
|
|
6
4
|
import type { ListViewProps } from './index'
|
|
7
5
|
|
|
8
6
|
type Props = ListViewProps
|
|
9
7
|
|
|
10
8
|
const { page } = Astro.props
|
|
11
|
-
const { collection, locale
|
|
9
|
+
const { collection, locale } = page
|
|
12
10
|
const urls = getUrls(Astro)
|
|
13
|
-
const site = await getRush(Astro).site.get()
|
|
14
|
-
const previous = page.page > 1 ? urls.collection(collection, locale, page.page - 1) : undefined
|
|
15
|
-
const next = page.page < lastPage ? urls.collection(collection, locale, page.page + 1) : undefined
|
|
16
|
-
const canonical = Astro.site && new URL(urls.collection(collection, locale, page.page), Astro.site)
|
|
17
|
-
const heading = page.page > 1 ? `${collection.name} (${page.page}/${lastPage})` : collection.name
|
|
18
|
-
const translations = collectionAlternates(collection.id, urls)
|
|
19
11
|
---
|
|
20
12
|
|
|
21
|
-
<
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
</p>
|
|
31
|
-
)
|
|
32
|
-
}
|
|
33
|
-
</header>
|
|
34
|
-
{
|
|
35
|
-
entries.items.length > 0 ? (
|
|
36
|
-
<ul class="mt-12 grid gap-6 sm:grid-cols-2 lg:grid-cols-3">
|
|
37
|
-
{entries.items.map((entry) => (
|
|
38
|
-
<li>
|
|
39
|
-
<article class="card group relative flex h-full flex-col">
|
|
40
|
-
{entry.featured_image?.url && (
|
|
41
|
-
<RushImage
|
|
42
|
-
media={entry.featured_image}
|
|
43
|
-
class="mb-4 aspect-video w-full rounded-lg object-cover"
|
|
44
|
-
/>
|
|
45
|
-
)}
|
|
46
|
-
<h2 class="text-lg font-medium group-hover:text-accent">
|
|
47
|
-
<a href={urls.servedPath(entry, locale)} class="after:absolute after:inset-0">
|
|
48
|
-
{entry.title}
|
|
49
|
-
</a>
|
|
50
|
-
</h2>
|
|
51
|
-
{entry.excerpt && <p class="mt-2 line-clamp-3 text-muted">{entry.excerpt}</p>}
|
|
52
|
-
<p class="mt-auto pt-4 text-sm text-muted">
|
|
53
|
-
<time datetime={entry.published_at}>
|
|
54
|
-
{formatDate(entry.published_at, locale)}
|
|
55
|
-
</time>
|
|
56
|
-
</p>
|
|
57
|
-
</article>
|
|
58
|
-
</li>
|
|
59
|
-
))}
|
|
60
|
-
</ul>
|
|
61
|
-
) : (
|
|
62
|
-
<p class="mt-12 text-muted">Nothing has been published here yet.</p>
|
|
63
|
-
)
|
|
64
|
-
}
|
|
65
|
-
{
|
|
66
|
-
lastPage > 1 && (
|
|
67
|
-
<nav aria-label="Pagination" class="mt-12 flex items-center justify-between gap-4">
|
|
68
|
-
{previous ? (
|
|
69
|
-
<a href={previous} rel="prev" class="button button-secondary">
|
|
70
|
-
Previous page
|
|
71
|
-
</a>
|
|
72
|
-
) : (
|
|
73
|
-
<span />
|
|
74
|
-
)}
|
|
75
|
-
{next && (
|
|
76
|
-
<a href={next} rel="next" class="button button-secondary">
|
|
77
|
-
Next page
|
|
78
|
-
</a>
|
|
79
|
-
)}
|
|
80
|
-
</nav>
|
|
81
|
-
)
|
|
82
|
-
}
|
|
83
|
-
</div>
|
|
84
|
-
</Base>
|
|
13
|
+
<ListPage
|
|
14
|
+
locale={locale}
|
|
15
|
+
title={collection.name}
|
|
16
|
+
page={page.page}
|
|
17
|
+
lastPage={page.lastPage}
|
|
18
|
+
entries={page.entries.items}
|
|
19
|
+
pageUrl={(number) => urls.collection(collection, locale, number)}
|
|
20
|
+
translations={collectionAlternates(collection.id, urls)}
|
|
21
|
+
/>
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import type { CollectionPage, HomepagePage } from '@rushcms/astro'
|
|
1
|
+
import type { CollectionPage, HomepagePage, TaxonomyPage } from '@rushcms/astro'
|
|
2
2
|
import type { CollectionRef, Entry, LocaleCode, RushUrls } from '@rushcms/client'
|
|
3
3
|
import GenericList from './collection.astro'
|
|
4
4
|
import GenericEntry from './entry.astro'
|
|
@@ -11,6 +11,10 @@ export type ListViewProps = {
|
|
|
11
11
|
page: CollectionPage
|
|
12
12
|
}
|
|
13
13
|
|
|
14
|
+
export type TaxonomyViewProps = {
|
|
15
|
+
page: TaxonomyPage
|
|
16
|
+
}
|
|
17
|
+
|
|
14
18
|
export type EntryViewProps = {
|
|
15
19
|
entry: Entry
|
|
16
20
|
locale: LocaleCode
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
---
|
|
2
|
+
import { getUrls } from '@rushcms/astro'
|
|
3
|
+
import ListPage from '../components/list-page.astro'
|
|
4
|
+
import type { TaxonomyViewProps } from './index'
|
|
5
|
+
|
|
6
|
+
type Props = TaxonomyViewProps
|
|
7
|
+
|
|
8
|
+
const { page } = Astro.props
|
|
9
|
+
const { tag, locale } = page
|
|
10
|
+
const urls = getUrls(Astro)
|
|
11
|
+
---
|
|
12
|
+
|
|
13
|
+
<ListPage
|
|
14
|
+
locale={locale}
|
|
15
|
+
title={tag.name}
|
|
16
|
+
page={page.page}
|
|
17
|
+
lastPage={page.lastPage}
|
|
18
|
+
entries={page.entries.items}
|
|
19
|
+
pageUrl={(number) => urls.taxonomy(tag, locale, number)}
|
|
20
|
+
translations={page.alternates}
|
|
21
|
+
/>
|