@plutocms/core 0.42.0 → 0.44.0
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/CHANGELOG.md +23 -0
- package/FEATURES.md +5 -5
- package/README.md +10 -10
- package/app/assets/css/pluto-layer.css +2 -2
- package/app/assets/css/pluto-site-theme.css +2 -2
- package/app/components/Pluto/Github/PlutoFieldMarkdown.vue +1 -1
- package/app/components/Pluto/Github/PlutoGithubSettingsPage.vue +1 -1
- package/app/components/Pluto/Github/PlutoGithubSetupPanel.vue +2 -2
- package/app/components/Pluto/Github/PlutoMarkdown.vue +1 -1
- package/app/components/Pluto/PlutoHtml.vue +1 -1
- package/app/components/Pluto/PlutoImage.vue +1 -1
- package/app/components/Pluto/Post/PlutoFieldPostCanvas.vue +1 -1
- package/app/plugins/pluto-core-registrations.ts +1 -1
- package/layers.ts +5 -14
- package/modules/pluto-css/css-entries.ts +14 -8
- package/modules/pluto-css/index.ts +26 -7
- package/modules/pluto-github/index.ts +8 -4
- package/modules/pluto-github/runtime/server/media.ts +1 -1
- package/modules/pluto-github/runtime/server/routes/media.get.ts +1 -1
- package/nuxt.config.ts +1 -1
- package/package.json +2 -2
- package/shared/types/content.ts +3 -3
- package/shared/utils/content-slug.ts +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -1,6 +1,29 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
3
|
|
|
4
|
+
## [0.44.0](https://github.com/plutocms/pluto/compare/v0.43.0...v0.44.0) (2026-11-01)
|
|
5
|
+
|
|
6
|
+
|
|
7
|
+
### Features
|
|
8
|
+
|
|
9
|
+
* import the Pluto CSS by name: @plutocms/css and @plutocms/css/site ([#336](https://github.com/plutocms/pluto/issues/336)) ([4d4b404](https://github.com/plutocms/pluto/commit/4d4b404070f186167e020bdcadf4e4df5d0948ef))
|
|
10
|
+
|
|
11
|
+
## [0.43.0](https://github.com/plutocms/pluto/compare/v0.42.0...v0.43.0) (2026-11-01)
|
|
12
|
+
|
|
13
|
+
|
|
14
|
+
### ⚠ BREAKING CHANGES
|
|
15
|
+
|
|
16
|
+
* the GitHub CMS is the Git CMS, and plutoLayer returns the source only ([#330](https://github.com/plutocms/pluto/issues/330))
|
|
17
|
+
|
|
18
|
+
### Features
|
|
19
|
+
|
|
20
|
+
* the GitHub CMS is the Git CMS, and plutoLayer returns the source only ([#330](https://github.com/plutocms/pluto/issues/330)) ([2aaedfe](https://github.com/plutocms/pluto/commit/2aaedfe32ad25e5e246994a998b0bfab32b63285))
|
|
21
|
+
|
|
22
|
+
|
|
23
|
+
### Bug Fixes
|
|
24
|
+
|
|
25
|
+
* plutoLayer finds the Supabase layers in the supabase monorepo ([#328](https://github.com/plutocms/pluto/issues/328)) ([62f79e7](https://github.com/plutocms/pluto/commit/62f79e789caf829981b8ac6a59f9475b50cfb9ca))
|
|
26
|
+
|
|
4
27
|
## [0.42.0](https://github.com/plutocms/pluto/compare/v0.41.0...v0.42.0) (2026-10-31)
|
|
5
28
|
|
|
6
29
|
|
package/FEATURES.md
CHANGED
|
@@ -18,7 +18,7 @@ policies shared by every project here.
|
|
|
18
18
|
delete routes backed by a `PlutoContentAdapter` a backend layer implements, and a generated
|
|
19
19
|
admin UI (list/form components, eight built-in field widgets, generated
|
|
20
20
|
`/admin/content/**` pages with catch-all id routes, `contentIdPath`, `listContentTypes`, and nav/pages
|
|
21
|
-
derivation). Real adapters exist: the supabase layer (PostgREST) and the
|
|
21
|
+
derivation). Real adapters exist: the supabase layer (PostgREST) and the Git CMS (Markdown files) each provide a `PlutoContentAdapter`.
|
|
22
22
|
@.claude/skills/content-model/SKILL.md
|
|
23
23
|
- Public API (headless): a versioned, read-only API for any framework or stack.
|
|
24
24
|
`GET /api/pluto/v1/content/<type>` and `/<type>/<id>` serve the published items of a type that sets
|
|
@@ -51,7 +51,7 @@ policies shared by every project here.
|
|
|
51
51
|
- Pluto UI tokens: the official palette (tholin, haze, heart, kuiper) and fonts (Public Sans,
|
|
52
52
|
Fredoka) in `@theme`, for every app. The admin theme is generated from them.
|
|
53
53
|
@.claude/skills/admin-theme/SKILL.md
|
|
54
|
-
- Pluto site theme: the opt-in
|
|
54
|
+
- Pluto site theme: the opt-in `@import '@plutocms/css/site'` gives a public site the look of the Pluto
|
|
55
55
|
docs (the fonts, the shades of the app colors, a deep-space dark mode, `pluto-sky`,
|
|
56
56
|
`pluto-site-header`). The official templates use it.
|
|
57
57
|
@.claude/skills/single-tailwind-build/SKILL.md
|
|
@@ -67,9 +67,9 @@ policies shared by every project here.
|
|
|
67
67
|
- Settings pages: `/admin/settings` is a section with tabs. A layer adds a tab with a `settingsPages` entry and a page file at `pages/admin/settings/<x>.vue`. The tabs show with 2 or more pages, the sidebar and the command palette list them, and a tab can need a capability (`'*'` is admin only). The capability picker groups by layer. @.claude/skills/extension-registry/SKILL.md
|
|
68
68
|
- Mail: a mail driver contract (`sendPlutoMail`, `registerMailDriver`) with Resend, dev (console and Mailpit) and none drivers, plain-TypeScript email templates (test, invite) translated by a server translator, and a guided `Settings > Email` page (admin only) that checks the key, adds and verifies a domain, and tests the setup. Secrets stay in the environment. @.claude/skills/mail/SKILL.md
|
|
69
69
|
- Single Tailwind build: the app owns the only Tailwind build. The pluto-css module generates
|
|
70
|
-
`#build/pluto.css` from each layer's `pluto-layer.css
|
|
70
|
+
`#build/pluto.css` from each layer's `pluto-layer.css` (the app imports it as `@plutocms/css`), adds a fallback entry, and warns
|
|
71
71
|
about a wrong CSS setup. @.claude/skills/single-tailwind-build/SKILL.md
|
|
72
|
-
-
|
|
72
|
+
- Git CMS: a standalone CMS with Markdown posts in a Git repo. Out of the box it publishes to the
|
|
73
73
|
local Git repo (dev only: each save is a local commit, `commit.local`); a GitHub App publishes
|
|
74
74
|
from a deployed site. The module is `pluto-github` (config
|
|
75
75
|
`plutoGithub`, env `NUXT_PLUTO_GITHUB_*` and `PLUTO_GITHUB_*`, routes `/api/_pluto/github/*`, names
|
|
@@ -96,7 +96,7 @@ policies shared by every project here.
|
|
|
96
96
|
and an Info popover with links to the Action or the build. A content type with `liveOnSave` shows
|
|
97
97
|
"Live" at once after a save and the static build as a small spinner. The file adapter has
|
|
98
98
|
`readFile` (safe relative paths) and `_frontmatter` on `get`, and core has the auto-imported
|
|
99
|
-
`markPublicRead(event)` for layers. @.claude/skills/
|
|
99
|
+
`markPublicRead(event)` for layers. @.claude/skills/git-cms/SKILL.md
|
|
100
100
|
- Lazy admin components: core registers its field widgets and dashboard widgets with
|
|
101
101
|
`defineAsyncComponent`, shows a skeleton per field, widget and settings panel while a chunk
|
|
102
102
|
loads, and warns in dev about a registered component that is not async.
|
package/README.md
CHANGED
|
@@ -28,13 +28,13 @@ npm install @plutocms/core
|
|
|
28
28
|
```ts
|
|
29
29
|
// nuxt.config.ts
|
|
30
30
|
export default defineNuxtConfig({
|
|
31
|
-
extends: [
|
|
31
|
+
extends: ['@plutocms/core'],
|
|
32
32
|
})
|
|
33
33
|
```
|
|
34
34
|
|
|
35
35
|
Core is the base layer every Pluto app extends. With no other layer, Pluto is a Markdown CMS on
|
|
36
36
|
Git: posts are files in your repository, and each save is a commit. It works out of the box with your local Git repo in development. Connect GitHub
|
|
37
|
-
to publish from a deployed site. See [
|
|
37
|
+
to publish from a deployed site. See [Git CMS](https://pluto.vulmix.dev/docs/git-cms/quickstart).
|
|
38
38
|
|
|
39
39
|
## Use it headless
|
|
40
40
|
|
|
@@ -48,14 +48,14 @@ See [Public API](https://pluto.vulmix.dev/docs/core/public-api).
|
|
|
48
48
|
|
|
49
49
|
## Layers
|
|
50
50
|
|
|
51
|
-
| Package | What it adds
|
|
52
|
-
| ------------------------- |
|
|
53
|
-
| `@plutocms/core` | The core: the admin, the content model, and the
|
|
54
|
-
| `@plutocms/docs` | A visual editor for the pages of a Nuxt Content site.
|
|
55
|
-
| `@plutocms/supabase` | A Supabase backend: database, auth, users, and roles.
|
|
56
|
-
| `@plutocms/supabase-blog` | Blog posts on Supabase.
|
|
57
|
-
| `@plutocms/supabase-shop` | Products on Supabase.
|
|
58
|
-
| `@plutocms/3d` | 3D models in the media library, and a viewer.
|
|
51
|
+
| Package | What it adds |
|
|
52
|
+
| ------------------------- | -------------------------------------------------------- |
|
|
53
|
+
| `@plutocms/core` | The core: the admin, the content model, and the Git CMS. |
|
|
54
|
+
| `@plutocms/docs` | A visual editor for the pages of a Nuxt Content site. |
|
|
55
|
+
| `@plutocms/supabase` | A Supabase backend: database, auth, users, and roles. |
|
|
56
|
+
| `@plutocms/supabase-blog` | Blog posts on Supabase. |
|
|
57
|
+
| `@plutocms/supabase-shop` | Products on Supabase. |
|
|
58
|
+
| `@plutocms/3d` | 3D models in the media library, and a viewer. |
|
|
59
59
|
|
|
60
60
|
Read [Layers](https://pluto.vulmix.dev/docs/core/layers) to see how they fit together.
|
|
61
61
|
|
|
@@ -5,9 +5,9 @@
|
|
|
5
5
|
*
|
|
6
6
|
* @import 'tailwindcss';
|
|
7
7
|
* @import '@nuxt/ui';
|
|
8
|
-
* @import '
|
|
8
|
+
* @import '@plutocms/css';
|
|
9
9
|
*
|
|
10
|
-
*
|
|
10
|
+
* `@plutocms/css` (core generates it) imports this file (and the same file of every other
|
|
11
11
|
* Pluto layer). Rules for this file:
|
|
12
12
|
* - Do not import tailwindcss or @nuxt/ui here.
|
|
13
13
|
* - Use only @theme, @custom-variant, @utility, unlayered rules, and
|
|
@@ -4,8 +4,8 @@
|
|
|
4
4
|
*
|
|
5
5
|
* @import 'tailwindcss';
|
|
6
6
|
* @import '@nuxt/ui';
|
|
7
|
-
* @import '
|
|
8
|
-
* @import '
|
|
7
|
+
* @import '@plutocms/css';
|
|
8
|
+
* @import '@plutocms/css/site';
|
|
9
9
|
*
|
|
10
10
|
* It does not choose the colors. Set them in app.config.ts, for example
|
|
11
11
|
* `ui.colors: { primary: 'tholin', secondary: 'haze', neutral: 'kuiper' }`. The rules below use
|
|
@@ -12,7 +12,7 @@ import PlutoMarkdownSource from './PlutoMarkdownSource.vue'
|
|
|
12
12
|
// when it saves. So the widget has a Source mode (`PlutoMarkdownSource`). The
|
|
13
13
|
// `editor` option of the field picks the first mode: `auto` (default) opens
|
|
14
14
|
// Source when the text has such syntax. Visual is off while the text has it.
|
|
15
|
-
// See the
|
|
15
|
+
// See the git-cms skill.
|
|
16
16
|
const props = defineProps<{
|
|
17
17
|
field: PlutoTextField
|
|
18
18
|
modelValue: unknown
|
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
// `/admin/settings/github` with `extendPages`, only when the CMS is on. The tab
|
|
4
4
|
// is the `settingsPages` entry of the CMS client plugin. The panel is the same
|
|
5
5
|
// checklist as the login card. In development, the Create button writes `.env`.
|
|
6
|
-
// The file lives under `app/` so Tailwind scans it. See the
|
|
6
|
+
// The file lives under `app/` so Tailwind scans it. See the git-cms skill.
|
|
7
7
|
const { t } = usePlutoI18n()
|
|
8
8
|
|
|
9
9
|
useHead({
|
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
// Install link and the docs link. The login card (`variant="login"`) and the
|
|
4
4
|
// GitHub settings page (`variant="settings"`) both use it. The file lives
|
|
5
5
|
// under `app/` so Tailwind scans it. The panel holds no secret: the status
|
|
6
|
-
// route answers booleans and public names only. See the
|
|
6
|
+
// route answers booleans and public names only. See the git-cms skill.
|
|
7
7
|
import type { PlutoGithubSetupStatus } from '../../../../modules/pluto-github/runtime/app/composables/pluto-github-setup'
|
|
8
8
|
import {
|
|
9
9
|
CMS_SETUP_START_URL,
|
|
@@ -22,7 +22,7 @@ const props = withDefaults(
|
|
|
22
22
|
}
|
|
23
23
|
)
|
|
24
24
|
|
|
25
|
-
const DOCS_URL = 'https://pluto.vulmix.dev/docs/
|
|
25
|
+
const DOCS_URL = 'https://pluto.vulmix.dev/docs/git-cms/quickstart'
|
|
26
26
|
|
|
27
27
|
const { t } = usePlutoI18n()
|
|
28
28
|
const setup = usePlutoGithubSetup()
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
<script setup lang="ts">
|
|
2
2
|
import PlutoHtml from '../PlutoHtml.vue'
|
|
3
3
|
|
|
4
|
-
// The
|
|
4
|
+
// The Git CMS name of `PlutoHtml`, kept for existing apps. New code uses `PlutoHtml`, which
|
|
5
5
|
// works with every backend. Attributes (for example `data-pluto-post-body`) pass through.
|
|
6
6
|
withDefaults(
|
|
7
7
|
defineProps<{
|
|
@@ -3,7 +3,7 @@ import { tv } from '@nuxt/ui/utils/tv'
|
|
|
3
3
|
import theme from '#build/ui/editor'
|
|
4
4
|
|
|
5
5
|
// Shows the `html` of a public item (the public API of Pluto), with readable prose styles. It
|
|
6
|
-
// works with every backend: the
|
|
6
|
+
// works with every backend: the Git CMS and `@plutocms/supabase-blog` both send the body as
|
|
7
7
|
// sanitized HTML, so the string is safe to set as `innerHTML`. This component never parses or
|
|
8
8
|
// sanitizes. Do not pass any other HTML to it.
|
|
9
9
|
const props = withDefaults(
|
|
@@ -5,7 +5,7 @@
|
|
|
5
5
|
// height of the record stop the layout from moving while the image loads.
|
|
6
6
|
//
|
|
7
7
|
// When the image service cannot read the file (for example a file of the
|
|
8
|
-
//
|
|
8
|
+
// Git CMS that is in the repo but not in a deploy yet), it shows the file
|
|
9
9
|
// as it is. A file that is not an image shows its preview image (the
|
|
10
10
|
// thumbnail of a 3D model), or nothing when it has none. See the media skill.
|
|
11
11
|
import type { PlutoPublicMedia } from '../../../shared/types/media'
|
|
@@ -11,7 +11,7 @@ import PlutoPostPreviewFrame from './PlutoPostPreviewFrame.vue'
|
|
|
11
11
|
// on the right. The compose panel shows one of two editors, and the switch in its
|
|
12
12
|
// footer picks it:
|
|
13
13
|
//
|
|
14
|
-
// - Visual: the rich text widget that the app has for `richtext` (the
|
|
14
|
+
// - Visual: the rich text widget that the app has for `richtext` (the Git CMS
|
|
15
15
|
// Markdown editor, or the editor of a layer), with `canvas`, so it fills the
|
|
16
16
|
// height and has no label.
|
|
17
17
|
// - Markdown: `PlutoMarkdownCodeEditor` (CodeMirror, with syntax colors). It loads
|
|
@@ -58,7 +58,7 @@ const PlutoContentBarActions = defineAsyncComponent(
|
|
|
58
58
|
// so a second `id: 'pluto'` call elsewhere would silently wipe this one out.
|
|
59
59
|
//
|
|
60
60
|
// `richtext` has no core widget here on purpose — a layer registers it (the
|
|
61
|
-
//
|
|
61
|
+
// Git CMS, the blog). `media` has the core widget: the picker of the core
|
|
62
62
|
// media library, for every backend (see the media skill).
|
|
63
63
|
//
|
|
64
64
|
// The Media page and its menu item show only when a backend has a media
|
package/layers.ts
CHANGED
|
@@ -11,27 +11,19 @@ import { isAbsolute, resolve } from 'node:path'
|
|
|
11
11
|
import process from 'node:process'
|
|
12
12
|
|
|
13
13
|
export interface PlutoLayerOptions {
|
|
14
|
-
/** Pass `install: true` to Nuxt, so it installs the layer dependencies. Default `true`. */
|
|
15
|
-
install?: boolean
|
|
16
14
|
/** The folder with the Pluto checkouts. It wins over `PLUTO_LOCAL_ROOT`. */
|
|
17
15
|
root?: string
|
|
18
16
|
}
|
|
19
17
|
|
|
20
|
-
export interface PlutoLayerEntryOptions {
|
|
21
|
-
install: boolean
|
|
22
|
-
}
|
|
23
|
-
|
|
24
|
-
export type PlutoLayerEntry = [source: string, options: PlutoLayerEntryOptions]
|
|
25
|
-
|
|
26
18
|
/**
|
|
27
19
|
* The checkout of each Pluto layer under the root. The key is the package name
|
|
28
20
|
* without the scope. A package of a monorepo is in a folder of its repo.
|
|
29
21
|
*/
|
|
30
22
|
export const PLUTO_LAYER_PATHS: Readonly<Record<string, string>> = {
|
|
31
23
|
core: 'pluto/packages/core',
|
|
32
|
-
supabase: 'supabase',
|
|
33
|
-
'supabase-shop': 'supabase-shop',
|
|
34
|
-
'supabase-blog': 'supabase-blog',
|
|
24
|
+
supabase: 'supabase/packages/supabase',
|
|
25
|
+
'supabase-shop': 'supabase/packages/supabase-shop',
|
|
26
|
+
'supabase-blog': 'supabase/packages/supabase-blog',
|
|
35
27
|
docs: 'pluto/packages/layers/docs',
|
|
36
28
|
'3d': 'pluto/packages/layers/addons/3d',
|
|
37
29
|
}
|
|
@@ -68,8 +60,7 @@ function checkoutOf(root: string, folder: string): string {
|
|
|
68
60
|
export function plutoLayer(
|
|
69
61
|
name: string,
|
|
70
62
|
options: PlutoLayerOptions = {}
|
|
71
|
-
):
|
|
72
|
-
const install = options.install ?? true
|
|
63
|
+
): string {
|
|
73
64
|
const envName = plutoLayerEnvName(name)
|
|
74
65
|
|
|
75
66
|
const rootValue = options.root || process.env.PLUTO_LOCAL_ROOT
|
|
@@ -90,5 +81,5 @@ export function plutoLayer(
|
|
|
90
81
|
}
|
|
91
82
|
}
|
|
92
83
|
|
|
93
|
-
return
|
|
84
|
+
return process.env[envName] || name
|
|
94
85
|
}
|
|
@@ -5,6 +5,12 @@ import { dirname, isAbsolute, join, relative, resolve } from 'node:path'
|
|
|
5
5
|
/** A layer's own CSS file, by convention. See the single-tailwind-build skill. */
|
|
6
6
|
export const LAYER_CSS_FILE = 'assets/css/pluto-layer.css'
|
|
7
7
|
|
|
8
|
+
/** The name that an app's CSS entry imports: an alias of `#build/pluto.css`. */
|
|
9
|
+
export const PLUTO_CSS_IMPORT = '@plutocms/css'
|
|
10
|
+
|
|
11
|
+
/** The opt-in Pluto site theme: an alias of `#build/pluto-site.css`. */
|
|
12
|
+
export const PLUTO_SITE_CSS_IMPORT = '@plutocms/css/site'
|
|
13
|
+
|
|
8
14
|
function toPosix(path: string): string {
|
|
9
15
|
return path.replaceAll('\\', '/')
|
|
10
16
|
}
|
|
@@ -41,7 +47,8 @@ export function renderPlutoCss(files: string[], buildDir: string): string {
|
|
|
41
47
|
|
|
42
48
|
/**
|
|
43
49
|
* Renders `#build/pluto-site.css`: the opt-in Pluto site theme of core
|
|
44
|
-
* (app/assets/css/pluto-site-theme.css). An app imports it
|
|
50
|
+
* (app/assets/css/pluto-site-theme.css). An app imports it (`@plutocms/css/site`)
|
|
51
|
+
* after `@plutocms/css`.
|
|
45
52
|
*/
|
|
46
53
|
export function renderPlutoSiteCss(file: string, buildDir: string): string {
|
|
47
54
|
return [
|
|
@@ -70,7 +77,7 @@ export function renderPlutoEntryCss(): string {
|
|
|
70
77
|
'/* Fallback Tailwind entry: the app has no CSS entry that imports Tailwind. */',
|
|
71
78
|
'@import "tailwindcss";',
|
|
72
79
|
'@import "@nuxt/ui";',
|
|
73
|
-
|
|
80
|
+
`@import "${PLUTO_CSS_IMPORT}";`,
|
|
74
81
|
'',
|
|
75
82
|
].join('\n')
|
|
76
83
|
}
|
|
@@ -106,7 +113,7 @@ export interface CssEntryInfo {
|
|
|
106
113
|
tailwind: boolean
|
|
107
114
|
/** It imports `@nuxt/ui`. */
|
|
108
115
|
nuxtUi: boolean
|
|
109
|
-
/** It imports `#build/pluto.css
|
|
116
|
+
/** It imports `@plutocms/css` (or the generated `#build/pluto.css` itself). */
|
|
110
117
|
plutoCss: boolean
|
|
111
118
|
}
|
|
112
119
|
|
|
@@ -145,8 +152,8 @@ export function analyzeCssEntry(
|
|
|
145
152
|
} else if (specifier === '@nuxt/ui') {
|
|
146
153
|
info.nuxtUi = true
|
|
147
154
|
} else if (
|
|
148
|
-
|
|
149
|
-
specifier.includes('#build')
|
|
155
|
+
specifier === PLUTO_CSS_IMPORT ||
|
|
156
|
+
(/(?:^|\/)pluto\.css$/.test(specifier) && specifier.includes('#build'))
|
|
150
157
|
) {
|
|
151
158
|
info.plutoCss = true
|
|
152
159
|
} else {
|
|
@@ -188,8 +195,7 @@ export function checkCssSetup(
|
|
|
188
195
|
): CssSetupReport {
|
|
189
196
|
const warnings: string[] = []
|
|
190
197
|
const tailwindEntries = entries.filter((entry) => entry.tailwind)
|
|
191
|
-
const snippet =
|
|
192
|
-
" @import 'tailwindcss';\n @import '@nuxt/ui';\n @import '#build/pluto.css';"
|
|
198
|
+
const snippet = ` @import 'tailwindcss';\n @import '@nuxt/ui';\n @import '${PLUTO_CSS_IMPORT}';`
|
|
193
199
|
|
|
194
200
|
if (tailwindEntries.length === 0) {
|
|
195
201
|
return { injectFallback: true, warnings }
|
|
@@ -214,7 +220,7 @@ export function checkCssSetup(
|
|
|
214
220
|
|
|
215
221
|
if (!tailwindEntries.some((entry) => entry.plutoCss)) {
|
|
216
222
|
warnings.push(
|
|
217
|
-
`No CSS entry imports
|
|
223
|
+
`No CSS entry imports ${PLUTO_CSS_IMPORT}. The admin theme and layer tokens are missing. Start the app's CSS entry with:\n${snippet}`
|
|
218
224
|
)
|
|
219
225
|
}
|
|
220
226
|
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { existsSync, readFileSync } from 'node:fs'
|
|
2
|
+
import { join } from 'node:path'
|
|
2
3
|
import { fileURLToPath } from 'node:url'
|
|
3
4
|
import {
|
|
4
5
|
addTemplate,
|
|
@@ -11,6 +12,8 @@ import {
|
|
|
11
12
|
analyzeCssEntry,
|
|
12
13
|
checkCssSetup,
|
|
13
14
|
findLayerCssFiles,
|
|
15
|
+
PLUTO_CSS_IMPORT,
|
|
16
|
+
PLUTO_SITE_CSS_IMPORT,
|
|
14
17
|
renderPlutoCss,
|
|
15
18
|
renderPlutoEntryCss,
|
|
16
19
|
renderPlutoSiteCss,
|
|
@@ -27,13 +30,17 @@ export interface PlutoCssOptions {
|
|
|
27
30
|
*
|
|
28
31
|
* @import 'tailwindcss';
|
|
29
32
|
* @import '@nuxt/ui';
|
|
30
|
-
* @import '
|
|
33
|
+
* @import '@plutocms/css';
|
|
31
34
|
*
|
|
32
|
-
* -
|
|
33
|
-
*
|
|
34
|
-
*
|
|
35
|
-
*
|
|
36
|
-
*
|
|
35
|
+
* - `@plutocms/css` is an alias of the generated `#build/pluto.css`. It imports
|
|
36
|
+
* each layer's app/assets/css/pluto-layer.css (tokens, the admin theme), so one
|
|
37
|
+
* import covers every layer of the app. Nuxt UI already adds `@source` for
|
|
38
|
+
* every layer's app/ dir, so this file adds no sources.
|
|
39
|
+
* - `@plutocms/css/site` (opt-in) is an alias of `#build/pluto-site.css`: the
|
|
40
|
+
* Pluto site theme of core (app/assets/css/pluto-site-theme.css), the look of
|
|
41
|
+
* the Pluto docs for a site.
|
|
42
|
+
* - The names are aliases, not npm packages, so they resolve with every package
|
|
43
|
+
* manager, also when the app installs only an outer layer.
|
|
37
44
|
* - An app with no Tailwind entry (a layer repo run on its own, or an app
|
|
38
45
|
* with no CSS) gets the fallback entry `#build/pluto-entry.css`.
|
|
39
46
|
* - The module warns about a layer that registers its own Tailwind build,
|
|
@@ -59,7 +66,7 @@ export default defineNuxtModule<PlutoCssOptions>({
|
|
|
59
66
|
})
|
|
60
67
|
|
|
61
68
|
// The opt-in site theme of core. An app that wants the look of the Pluto
|
|
62
|
-
// docs imports
|
|
69
|
+
// docs imports `@plutocms/css/site` after `@plutocms/css`.
|
|
63
70
|
const siteTheme = fileURLToPath(
|
|
64
71
|
new URL('../../app/assets/css/pluto-site-theme.css', import.meta.url)
|
|
65
72
|
)
|
|
@@ -69,6 +76,18 @@ export default defineNuxtModule<PlutoCssOptions>({
|
|
|
69
76
|
getContents: () => renderPlutoSiteCss(siteTheme, nuxt.options.buildDir),
|
|
70
77
|
})
|
|
71
78
|
|
|
79
|
+
// The names that an app's CSS entry imports. Tailwind resolves `@import`
|
|
80
|
+
// through the Vite aliases. `/site` comes first: an alias also matches the
|
|
81
|
+
// paths under its name, so `@plutocms/css` would take `@plutocms/css/site`.
|
|
82
|
+
nuxt.options.alias[PLUTO_SITE_CSS_IMPORT] = join(
|
|
83
|
+
nuxt.options.buildDir,
|
|
84
|
+
'pluto-site.css'
|
|
85
|
+
)
|
|
86
|
+
nuxt.options.alias[PLUTO_CSS_IMPORT] = join(
|
|
87
|
+
nuxt.options.buildDir,
|
|
88
|
+
'pluto.css'
|
|
89
|
+
)
|
|
90
|
+
|
|
72
91
|
addTemplate({
|
|
73
92
|
filename: 'pluto-entry.css',
|
|
74
93
|
write: true,
|
|
@@ -30,7 +30,7 @@ interface LayerConfigMeta {
|
|
|
30
30
|
* Pluto admin. `plutoGithub.enabled` is `'auto'` by default: the CMS is on unless
|
|
31
31
|
* a backend layer is present or the app sets `false`. An explicit `true` with a
|
|
32
32
|
* backend layer logs an error. When the CMS is off, the module adds nothing to
|
|
33
|
-
* the app. See the
|
|
33
|
+
* the app. See the git-cms skill.
|
|
34
34
|
*/
|
|
35
35
|
export default defineNuxtModule<PlutoGithubOptions>({
|
|
36
36
|
meta: { name: 'pluto-github', configKey: 'plutoGithub' },
|
|
@@ -120,8 +120,12 @@ export default defineNuxtModule<PlutoGithubOptions>({
|
|
|
120
120
|
skipDeploy: resolved.commit.skipDeploy,
|
|
121
121
|
}
|
|
122
122
|
// The media library of core uses the GitHub driver (runtime/server/media.ts).
|
|
123
|
-
const media = nuxt.options.runtimeConfig.public.plutoMedia as
|
|
124
|
-
|
|
123
|
+
const media = nuxt.options.runtimeConfig.public.plutoMedia as
|
|
124
|
+
Record<string, unknown> | undefined
|
|
125
|
+
nuxt.options.runtimeConfig.public.plutoMedia = {
|
|
126
|
+
...media,
|
|
127
|
+
driver: 'github',
|
|
128
|
+
} as typeof nuxt.options.runtimeConfig.public.plutoMedia
|
|
125
129
|
|
|
126
130
|
const resolver = createResolver(import.meta.url)
|
|
127
131
|
const server = (file: string) => resolver.resolve('./runtime/server', file)
|
|
@@ -195,7 +199,7 @@ export default defineNuxtModule<PlutoGithubOptions>({
|
|
|
195
199
|
}
|
|
196
200
|
})
|
|
197
201
|
|
|
198
|
-
// Setup routes: the checks and the App Manifest flow. See the
|
|
202
|
+
// Setup routes: the checks and the App Manifest flow. See the git-cms skill.
|
|
199
203
|
// They are static, so they win over the `:type/:slug` route below.
|
|
200
204
|
addServerHandler({
|
|
201
205
|
route: '/api/_pluto/github/setup/status',
|
|
@@ -64,7 +64,7 @@ function numberOrNull(value: unknown): number | null {
|
|
|
64
64
|
}
|
|
65
65
|
|
|
66
66
|
/**
|
|
67
|
-
* The media driver of the
|
|
67
|
+
* The media driver of the Git CMS. A file and its record go into the repo
|
|
68
68
|
* in one commit:
|
|
69
69
|
*
|
|
70
70
|
* - the file: `public/media/<yyyy>/<mm>/<name>-<suffix>.<ext>`, served at
|
|
@@ -11,7 +11,7 @@ import {
|
|
|
11
11
|
} from '../utils/github-setup'
|
|
12
12
|
|
|
13
13
|
/**
|
|
14
|
-
* Route: GET /media/**. A media file of the
|
|
14
|
+
* Route: GET /media/**. A media file of the Git CMS, read from the repo.
|
|
15
15
|
* After a deploy, the host sends the static file first, so this route only
|
|
16
16
|
* answers for a file that is in the repo but not in a deploy yet (a content
|
|
17
17
|
* commit can skip the deploy). A stored file name never changes, so the
|
package/nuxt.config.ts
CHANGED
|
@@ -43,7 +43,7 @@ export default defineNuxtConfig({
|
|
|
43
43
|
|
|
44
44
|
// No `css` entry: the app's CSS entry owns the one Tailwind build, and
|
|
45
45
|
// modules/pluto-css adds this layer's pluto-layer.css to it through
|
|
46
|
-
// #build/pluto.css. See the single-tailwind-build skill.
|
|
46
|
+
// @plutocms/css (#build/pluto.css). See the single-tailwind-build skill.
|
|
47
47
|
|
|
48
48
|
runtimeConfig: {
|
|
49
49
|
// Private mail settings. Empty defaults on purpose: Nuxt reads
|
package/package.json
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@plutocms/core",
|
|
3
3
|
"type": "module",
|
|
4
|
-
"version": "0.
|
|
5
|
-
"description": "The base layer every Pluto app extends: the admin, the content model, and the
|
|
4
|
+
"version": "0.44.0",
|
|
5
|
+
"description": "The base layer every Pluto app extends: the admin, the content model, and the Git CMS",
|
|
6
6
|
"author": "Victor Ribeiro",
|
|
7
7
|
"license": "MIT",
|
|
8
8
|
"homepage": "https://github.com/plutocms/pluto/tree/main/packages/core#readme",
|
package/shared/types/content.ts
CHANGED
|
@@ -54,7 +54,7 @@ export interface PlutoTextField extends PlutoFieldBase {
|
|
|
54
54
|
/** Only for `textarea`. The box grows with the text up to this many rows, then it scrolls. Default 14. */
|
|
55
55
|
maxRows?: number
|
|
56
56
|
/**
|
|
57
|
-
* Only for `richtext` in the
|
|
57
|
+
* Only for `richtext` in the Git CMS (the Markdown widget). `'visual'` opens the rich editor. `'source'` opens the
|
|
58
58
|
* raw Markdown text. `'auto'` (default) opens the source when the text has syntax that the rich editor
|
|
59
59
|
* cannot keep (MDC, HTML, tables, task lists, footnotes). The widget has a Visual/Source switch, and it
|
|
60
60
|
* disables Visual while the text has such syntax.
|
|
@@ -265,7 +265,7 @@ export interface PlutoContentType {
|
|
|
265
265
|
previewUrl?: (item: PlutoContentItem) => string | undefined
|
|
266
266
|
/**
|
|
267
267
|
* The public site shows a save at once, because it reads this type at run time. A deploy may
|
|
268
|
-
* still run. The build indicator of the edit form (
|
|
268
|
+
* still run. The build indicator of the edit form (Git CMS) then shows "Live" right after a
|
|
269
269
|
* save, and shows the static build by a small spinner on the Info button. Default false: the
|
|
270
270
|
* indicator waits for the build and shows "Publishing…".
|
|
271
271
|
*/
|
|
@@ -303,7 +303,7 @@ export interface PlutoContentType {
|
|
|
303
303
|
width?: 'container' | 'full'
|
|
304
304
|
}
|
|
305
305
|
/**
|
|
306
|
-
* Options for the file adapters (the
|
|
306
|
+
* Options for the file adapters (the Git CMS). Other adapters ignore them. Every member is
|
|
307
307
|
* plain data or a pure function, so the definition is safe on the server and on the client.
|
|
308
308
|
*/
|
|
309
309
|
files?: PlutoContentFiles
|
|
@@ -6,7 +6,7 @@ export const SLUG_MAX_LENGTH = 100
|
|
|
6
6
|
* "pao-de-mel". The result is lowercase ASCII, with single dashes. It can
|
|
7
7
|
* be an empty string.
|
|
8
8
|
*
|
|
9
|
-
* The form and the
|
|
9
|
+
* The form and the Git CMS both use this function.
|
|
10
10
|
*/
|
|
11
11
|
export function slugifyTitle(value: string): string {
|
|
12
12
|
return value
|