@plutocms/core 0.39.0 → 0.39.2
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 +14 -0
- package/README.md +1 -1
- package/app/components/Pluto/Admin/PlutoAdminNavbar.vue +15 -13
- package/app/components/Pluto/Content/PlutoContentBarActions.vue +15 -1
- package/app/components/Pluto/Markdown/PlutoMarkdownCodeEditor.vue +1 -1
- package/app/components/Pluto/Post/PlutoFieldPostCanvas.vue +1 -1
- package/app/pages/_pluto/post-preview.vue +1 -1
- package/layers.ts +1 -1
- package/nuxt.config.ts +2 -10
- package/package.json +2 -11
- package/shared/utils/preview-path.ts +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -1,6 +1,20 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
3
|
|
|
4
|
+
## [0.39.2](https://github.com/plutocms/pluto/compare/v0.39.1...v0.39.2) (2026-10-31)
|
|
5
|
+
|
|
6
|
+
|
|
7
|
+
### Bug Fixes
|
|
8
|
+
|
|
9
|
+
* plutoLayer finds the checkout of @plutocms/docs (the renamed nuxt-content layer) ([#306](https://github.com/plutocms/pluto/issues/306)) ([ef9707e](https://github.com/plutocms/pluto/commit/ef9707e551176973c00acd4102fe55a2e5d07c87))
|
|
10
|
+
|
|
11
|
+
## [0.39.1](https://github.com/plutocms/pluto/compare/v0.39.0...v0.39.1) (2026-10-31)
|
|
12
|
+
|
|
13
|
+
|
|
14
|
+
### Bug Fixes
|
|
15
|
+
|
|
16
|
+
* **admin:** navbar spinner icon, no focus ring after a hover menu, Pluto mark only ([#299](https://github.com/plutocms/pluto/issues/299)) ([6c87c62](https://github.com/plutocms/pluto/commit/6c87c62e73b633607f3ab13e478aa9711709b446))
|
|
17
|
+
|
|
4
18
|
## [0.39.0](https://github.com/plutocms/pluto/compare/v0.38.2...v0.39.0) (2026-10-31)
|
|
5
19
|
|
|
6
20
|
|
package/README.md
CHANGED
|
@@ -51,7 +51,7 @@ See [Public API](https://pluto.vulmix.dev/docs/core/public-api).
|
|
|
51
51
|
| Package | What it adds |
|
|
52
52
|
| ------------------------- | ----------------------------------------------------------- |
|
|
53
53
|
| `@plutocms/core` | The core: the admin, the content model, and the GitHub CMS. |
|
|
54
|
-
| `@plutocms/
|
|
54
|
+
| `@plutocms/docs` | A visual editor for the pages of a Nuxt Content site. |
|
|
55
55
|
| `@plutocms/supabase` | A Supabase backend: database, auth, users, and roles. |
|
|
56
56
|
| `@plutocms/supabase-blog` | Blog posts on Supabase. |
|
|
57
57
|
| `@plutocms/supabase-shop` | Products on Supabase. |
|
|
@@ -46,7 +46,10 @@ const siteDomain = computed(() => domainFromUrl(site.url.value) || host)
|
|
|
46
46
|
to="/admin/home"
|
|
47
47
|
class="group outline-inverted/40 flex h-full items-center gap-x-2 rounded-sm focus-visible:outline-2 focus-visible:-outline-offset-2"
|
|
48
48
|
>
|
|
49
|
-
<!--
|
|
49
|
+
<!--
|
|
50
|
+
A brand logo (white label), its mark only on a small screen. Else the Pluto
|
|
51
|
+
mark: the site chip next to it names the site.
|
|
52
|
+
-->
|
|
50
53
|
<template v-if="brandLogo">
|
|
51
54
|
<img
|
|
52
55
|
:src="brandMark"
|
|
@@ -59,17 +62,12 @@ const siteDomain = computed(() => domainFromUrl(site.url.value) || host)
|
|
|
59
62
|
class="hidden h-7 w-auto max-w-40 object-contain sm:block"
|
|
60
63
|
/>
|
|
61
64
|
</template>
|
|
62
|
-
<
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
<PlutoLogo
|
|
69
|
-
aria-hidden="true"
|
|
70
|
-
class="text-highlighted hidden h-7.75 w-auto grayscale-100 group-hover:grayscale-0 sm:block"
|
|
71
|
-
/>
|
|
72
|
-
</template>
|
|
65
|
+
<PlutoLogo
|
|
66
|
+
v-else
|
|
67
|
+
aria-hidden="true"
|
|
68
|
+
class="block h-6.75 w-auto grayscale-100 group-hover:grayscale-0"
|
|
69
|
+
mark
|
|
70
|
+
/>
|
|
73
71
|
<!-- The site that this admin edits, as a chip. -->
|
|
74
72
|
<span
|
|
75
73
|
v-if="siteName"
|
|
@@ -102,7 +100,11 @@ const siteDomain = computed(() => domainFromUrl(site.url.value) || host)
|
|
|
102
100
|
<div
|
|
103
101
|
class="text-dimmed flex h-full items-center gap-x-2 rounded-sm px-2"
|
|
104
102
|
>
|
|
105
|
-
|
|
103
|
+
<!-- Lucide: an app's icon bundle always has it. -->
|
|
104
|
+
<Icon
|
|
105
|
+
name="i-lucide-loader-circle"
|
|
106
|
+
class="size-4 animate-spin"
|
|
107
|
+
/>
|
|
106
108
|
</div>
|
|
107
109
|
</li>
|
|
108
110
|
</template>
|
|
@@ -33,6 +33,10 @@ const menuOpen = ref(false)
|
|
|
33
33
|
// True while the menu is open because of a hover. A click on the button then
|
|
34
34
|
// keeps it open, instead of toggling it closed. The pointer leaving closes it.
|
|
35
35
|
let openedByHover = false
|
|
36
|
+
// True when the last open was a hover. Then the close does not move the focus
|
|
37
|
+
// back to the button: the focus ring would stay on it after the pointer left.
|
|
38
|
+
// A menu opened by a click or the keyboard returns the focus, as before.
|
|
39
|
+
let skipFocusReturn = false
|
|
36
40
|
let openTimer: ReturnType<typeof setTimeout> | undefined
|
|
37
41
|
let closeTimer: ReturnType<typeof setTimeout> | undefined
|
|
38
42
|
// The time until which a close request is ignored (see onUpdateOpen).
|
|
@@ -52,6 +56,7 @@ function onHoverEnter(event: PointerEvent) {
|
|
|
52
56
|
openTimer = setTimeout(() => {
|
|
53
57
|
if (!menuOpen.value) {
|
|
54
58
|
openedByHover = true
|
|
59
|
+
skipFocusReturn = true
|
|
55
60
|
menuOpen.value = true
|
|
56
61
|
}
|
|
57
62
|
}, HOVER_OPEN_DELAY)
|
|
@@ -97,9 +102,18 @@ function onUpdateOpen(open: boolean) {
|
|
|
97
102
|
if (!open && Date.now() < confirmUntil) {
|
|
98
103
|
return
|
|
99
104
|
}
|
|
105
|
+
if (open) {
|
|
106
|
+
skipFocusReturn = false
|
|
107
|
+
}
|
|
100
108
|
menuOpen.value = open
|
|
101
109
|
}
|
|
102
110
|
|
|
111
|
+
function onCloseAutoFocus(event: Event) {
|
|
112
|
+
if (skipFocusReturn) {
|
|
113
|
+
event.preventDefault()
|
|
114
|
+
}
|
|
115
|
+
}
|
|
116
|
+
|
|
103
117
|
function onTriggerMouseDown(event: MouseEvent) {
|
|
104
118
|
if (keepsHoverMenu(event)) {
|
|
105
119
|
event.preventDefault()
|
|
@@ -200,7 +214,7 @@ const editButton = computed(() => {
|
|
|
200
214
|
<UDropdownMenu
|
|
201
215
|
:open="menuOpen"
|
|
202
216
|
:items="newMenuItems"
|
|
203
|
-
:content="{ align: 'start' }"
|
|
217
|
+
:content="{ align: 'start', onCloseAutoFocus }"
|
|
204
218
|
:modal="false"
|
|
205
219
|
:portal="portalTarget ?? true"
|
|
206
220
|
:ui="{ content: 'min-w-48' }"
|
|
@@ -5,7 +5,7 @@ import type { Extension, Range } from '@codemirror/state'
|
|
|
5
5
|
// headings, links and code. The marks (`**`, `#`, `[`) stay, a little dimmed.
|
|
6
6
|
// The MDC lines get a color: the components (`::name`), the slots (`#title`)
|
|
7
7
|
// and the YAML props. A toolbar has the quick formats, with their shortcuts.
|
|
8
|
-
// The post editor and the page editor of the
|
|
8
|
+
// The post editor and the page editor of the docs layer use it.
|
|
9
9
|
//
|
|
10
10
|
// The model value is the Markdown text, as it is: the editor changes only what
|
|
11
11
|
// the author types. `insert`, `focus`, `reveal` and `goToLine` are exposed, and
|
|
@@ -5,7 +5,7 @@ import PlutoPostOutline from './PlutoPostOutline.vue'
|
|
|
5
5
|
import PlutoPostPreviewFrame from './PlutoPostPreviewFrame.vue'
|
|
6
6
|
|
|
7
7
|
// The `post-canvas` widget: the body of a post (a Markdown `richtext` field) in the
|
|
8
|
-
// canvas layout of the content form, like the page editor of the
|
|
8
|
+
// canvas layout of the content form, like the page editor of the docs layer.
|
|
9
9
|
//
|
|
10
10
|
// The canvas is a split: the compose panel on the left, the live preview of the site
|
|
11
11
|
// on the right. The compose panel shows one of two editors, and the switch in its
|
|
@@ -16,7 +16,7 @@ useHead({
|
|
|
16
16
|
{ textContent: 'a { pointer-events: none; }' },
|
|
17
17
|
{
|
|
18
18
|
// A thin scrollbar that fits the editor, in both color modes: a gray thumb on no track.
|
|
19
|
-
// The same as the page preview of the
|
|
19
|
+
// The same as the page preview of the docs layer.
|
|
20
20
|
textContent: [
|
|
21
21
|
'html { scrollbar-width: thin; scrollbar-color: rgb(128 128 128 / 0.45) transparent; }',
|
|
22
22
|
'html::-webkit-scrollbar { width: 10px; }',
|
package/layers.ts
CHANGED
|
@@ -33,7 +33,7 @@ export const PLUTO_LAYER_PATHS: Readonly<Record<string, string>> = {
|
|
|
33
33
|
supabase: 'supabase',
|
|
34
34
|
'supabase-shop': 'supabase-shop',
|
|
35
35
|
'supabase-blog': 'supabase-blog',
|
|
36
|
-
|
|
36
|
+
docs: 'docs',
|
|
37
37
|
'3d': 'pluto/packages/layers/addons/3d',
|
|
38
38
|
}
|
|
39
39
|
|
package/nuxt.config.ts
CHANGED
|
@@ -8,8 +8,9 @@ const utilsLayer = process.env.PLUTO_UTILS_PATH || '@plutocms/utils'
|
|
|
8
8
|
export default defineNuxtConfig({
|
|
9
9
|
extends: [utilsLayer],
|
|
10
10
|
|
|
11
|
+
// No @nuxt/eslint: a module of a layer runs in every app that extends it. The
|
|
12
|
+
// repo lints with @nuxt/eslint-config (eslint.config.mjs at the root).
|
|
11
13
|
modules: [
|
|
12
|
-
'@nuxt/eslint',
|
|
13
14
|
'@nuxt/image',
|
|
14
15
|
'@nuxt/ui',
|
|
15
16
|
'@vueuse/nuxt',
|
|
@@ -107,15 +108,6 @@ export default defineNuxtConfig({
|
|
|
107
108
|
typeCheck: false,
|
|
108
109
|
},
|
|
109
110
|
|
|
110
|
-
eslint: {
|
|
111
|
-
config: {
|
|
112
|
-
nuxt: {
|
|
113
|
-
sortConfigKeys: true,
|
|
114
|
-
},
|
|
115
|
-
standalone: false,
|
|
116
|
-
},
|
|
117
|
-
},
|
|
118
|
-
|
|
119
111
|
// Modules configurations
|
|
120
112
|
fonts: {
|
|
121
113
|
defaults: {
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@plutocms/core",
|
|
3
3
|
"type": "module",
|
|
4
|
-
"version": "0.39.
|
|
4
|
+
"version": "0.39.2",
|
|
5
5
|
"description": "The base layer every Pluto app extends: the admin, the content model, and the GitHub CMS",
|
|
6
6
|
"author": "Victor Ribeiro",
|
|
7
7
|
"license": "MIT",
|
|
@@ -27,18 +27,10 @@
|
|
|
27
27
|
"dev": "nuxt dev --no-fork",
|
|
28
28
|
"generate": "nuxt generate",
|
|
29
29
|
"preview": "nuxt preview",
|
|
30
|
-
"
|
|
30
|
+
"dev:prepare": "nuxt prepare",
|
|
31
31
|
"typecheck": "nuxt prepare && vue-tsc -b --noEmit",
|
|
32
32
|
"test": "vitest run"
|
|
33
33
|
},
|
|
34
|
-
"trustedDependencies": [
|
|
35
|
-
"@parcel/watcher",
|
|
36
|
-
"@plutocms/utils",
|
|
37
|
-
"@tailwindcss/oxide",
|
|
38
|
-
"esbuild",
|
|
39
|
-
"unrs-resolver",
|
|
40
|
-
"vue-demi"
|
|
41
|
-
],
|
|
42
34
|
"dependencies": {
|
|
43
35
|
"@codemirror/commands": "^6.11.1",
|
|
44
36
|
"@codemirror/lang-markdown": "^6.5.2",
|
|
@@ -49,7 +41,6 @@
|
|
|
49
41
|
"@iconify-json/lucide": "^1.2.144",
|
|
50
42
|
"@internationalized/date": "^3.12.4",
|
|
51
43
|
"@lezer/highlight": "^1.2.5",
|
|
52
|
-
"@nuxt/eslint": "^1.17.0",
|
|
53
44
|
"@nuxt/image": "^2.1.0",
|
|
54
45
|
"@nuxt/ui": "^4.12.0",
|
|
55
46
|
"@plutocms/utils": ">=0.3.0 <1.0.0",
|
|
@@ -3,7 +3,7 @@ export const PLUTO_PREVIEW_PATH = '/_pluto/preview'
|
|
|
3
3
|
|
|
4
4
|
/**
|
|
5
5
|
* The path of the post preview that the post editor (`post-canvas`) shows in an iframe. It is not
|
|
6
|
-
* below `PLUTO_PREVIEW_PATH`: the
|
|
6
|
+
* below `PLUTO_PREVIEW_PATH`: the docs layer has a page there, and a page below it would
|
|
7
7
|
* be a child route of that page.
|
|
8
8
|
*/
|
|
9
9
|
export const PLUTO_POST_PREVIEW_PATH = '/_pluto/post-preview'
|