caracms 0.3.0 → 0.3.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 CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "caracms",
3
- "version": "0.3.0",
3
+ "version": "0.3.1",
4
4
  "description": "A visual CMS for Astro sites, with content in git.",
5
5
  "license": "MIT",
6
6
  "type": "module",
@@ -11,7 +11,7 @@
11
11
  * offers, a collection's singular word, a document's public address.
12
12
  */
13
13
  import { titleCase } from '../../../fields.ts';
14
- import { slugify } from '../../../slug.ts';
14
+ import { RESERVED_SLUG, slugify } from '../../../slug.ts';
15
15
  import type { Editor } from '../editor.ts';
16
16
  import { docId, ENDPOINTS, MEDIA_ENDPOINTS, TAB_HEADER, sameDoc, type CreateDeleteRefusal, type CreateRequest, type CreateResponse, type DeleteResponse, type DocRef, type MoveResponse, type EditorAnyCollection, type ListedDocument, type ReplaceFileResponse } from '../../types.ts';
17
17
 
@@ -155,8 +155,9 @@ export interface InsideOption {
155
155
  }
156
156
 
157
157
  /**
158
- * New page's "Inside" (Decision 11): the top level, then every folder that holds pages
159
- * (a group, or a page with pages under it), at any depth, in tree order.
158
+ * New page's "Inside" (Decision 11): the top level, then every group and every page, at
159
+ * any depth, in tree order. A page with nothing under it yet is offered too, so a page can
160
+ * go under it (Urban Return, 2026-10-24); Home isn't, since no address goes under `/index/`.
160
161
  */
161
162
  export function insideOptions(collection: Pick<EditorAnyCollection, 'name' | 'urlBase'>, documents: readonly ListedDocument[]): InsideOption[] {
162
163
  const base = collection.urlBase ?? '/';
@@ -164,8 +165,9 @@ export function insideOptions(collection: Pick<EditorAnyCollection, 'name' | 'ur
164
165
  const folders = new Set<string>();
165
166
  for (const d of docs) {
166
167
  const parts = d.path.split('/');
167
- for (let i = 1; i < parts.length; i++) folders.add(parts.slice(0, i).join('/'));
168
+ for (let i = 1; i <= parts.length; i++) folders.add(parts.slice(0, i).join('/'));
168
169
  }
170
+ for (const f of folders) if (f.split('/').includes(RESERVED_SLUG)) folders.delete(f);
169
171
  const labelOf = (path: string) => docs.find((d) => d.path === path)?.label ?? titleCase(path.split('/').pop()!);
170
172
  const options = [...folders]
171
173
  .sort((a, b) => a.localeCompare(b))
@@ -311,7 +311,8 @@ function MoveDocument({ docRef }: { docRef: DocRef }) {
311
311
  const [part, setPart] = useState(docRef.path.slice(slash + 1));
312
312
  const [error, setError] = useState<string | null>(null);
313
313
  const [busy, setBusy] = useState(false);
314
- const options = useMemo(() => (collection?.nested ? insideOptions(collection, documents) : []), [collection, documents]);
314
+ // Every page but this one: a page can't go under itself.
315
+ const options = useMemo(() => (collection?.nested ? insideOptions(collection, documents).filter((o) => o.path !== docRef.path) : []), [collection, documents, docRef.path]);
315
316
  if (!doc || !collection || !doc.url) return null;
316
317
  const nested = collection.nested;
317
318
  const newGroup = nested && inside === NEW_GROUP;