nca-ai-cms-astro-plugin 1.1.0 → 1.1.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": "nca-ai-cms-astro-plugin",
3
- "version": "1.1.0",
3
+ "version": "1.1.1",
4
4
  "type": "module",
5
5
  "exports": {
6
6
  ".": "./src/index.ts",
@@ -1,13 +1,24 @@
1
1
  ---
2
2
  interface Props {
3
3
  isAuthenticated?: boolean;
4
+ currentPath?: string;
4
5
  }
5
6
 
6
- const { isAuthenticated } = Astro.props;
7
+ const { isAuthenticated, currentPath = '' } = Astro.props;
8
+
9
+ // Extract context from current path for smart defaults
10
+ // /services/gleitschleifen → "Gleitschleifen"
11
+ // /services/laserreinigung → "Laserreinigung"
12
+ let pageContext = '';
13
+ const serviceMatch = currentPath.match(/^\/services\/([^/]+)/);
14
+ if (serviceMatch) {
15
+ const slug = serviceMatch[1];
16
+ pageContext = slug.charAt(0).toUpperCase() + slug.slice(1).replace(/-/g, ' ');
17
+ }
7
18
  ---
8
19
 
9
20
  {isAuthenticated && (
10
- <div id="editor-toolbar">
21
+ <div id="editor-toolbar" data-page-context={pageContext}>
11
22
  <!-- FAB Button -->
12
23
  <button
13
24
  id="editor-fab"
@@ -33,13 +44,23 @@ const { isAuthenticated } = Astro.props;
33
44
  </button>
34
45
  </div>
35
46
 
47
+ {pageContext && (
48
+ <div class="editor-context-badge">
49
+ <svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
50
+ <path d="M21 10c0 7-9 13-9 13s-9-6-9-13a9 9 0 0 1 18 0z" />
51
+ <circle cx="12" cy="10" r="3" />
52
+ </svg>
53
+ <span>Kontext: {pageContext}</span>
54
+ </div>
55
+ )}
56
+
36
57
  <form id="editor-create-form">
37
58
  <label for="editor-input-topic">Thema oder Keyword</label>
38
59
  <input
39
60
  type="text"
40
61
  id="editor-input-topic"
41
62
  name="input"
42
- placeholder="z.B. Laserreinigung"
63
+ placeholder={pageContext ? `z.B. ${pageContext} Kosten, ${pageContext} Vorteile` : 'z.B. Laserreinigung'}
43
64
  required
44
65
  autocomplete="off"
45
66
  />
@@ -149,6 +170,20 @@ const { isAuthenticated } = Astro.props;
149
170
  background: #f1f5f9;
150
171
  }
151
172
 
173
+ .editor-context-badge {
174
+ display: flex;
175
+ align-items: center;
176
+ gap: 6px;
177
+ margin: 0 20px;
178
+ padding: 8px 12px;
179
+ background: #eff6ff;
180
+ border-radius: 6px;
181
+ font-size: 12px;
182
+ font-weight: 500;
183
+ color: #1d4ed8;
184
+ margin-top: 12px;
185
+ }
186
+
152
187
  #editor-create-form {
153
188
  padding: 20px;
154
189
  }
@@ -283,6 +318,7 @@ const { isAuthenticated } = Astro.props;
283
318
  </style>
284
319
 
285
320
  <script>
321
+ const toolbar = document.getElementById('editor-toolbar') as HTMLElement;
286
322
  const fab = document.getElementById('editor-fab') as HTMLButtonElement;
287
323
  const panel = document.getElementById('editor-panel') as HTMLElement;
288
324
  const closeBtn = document.getElementById('editor-panel-close') as HTMLButtonElement;
@@ -294,7 +330,9 @@ const { isAuthenticated } = Astro.props;
294
330
  const topicInput = document.getElementById('editor-input-topic') as HTMLInputElement;
295
331
  const notesInput = document.getElementById('editor-input-notes') as HTMLTextAreaElement;
296
332
 
297
- if (fab && panel) {
333
+ if (fab && panel && toolbar) {
334
+ const pageContext = toolbar.dataset.pageContext || '';
335
+
298
336
  const togglePanel = () => {
299
337
  const isOpen = !panel.hidden;
300
338
  panel.hidden = isOpen;
@@ -307,12 +345,6 @@ const { isAuthenticated } = Astro.props;
307
345
  fab.addEventListener('click', togglePanel);
308
346
  closeBtn?.addEventListener('click', togglePanel);
309
347
 
310
- // Close on Escape
311
- document.addEventListener('keydown', (e) => {
312
- if (e.key === 'Escape' && !panel.hidden) {
313
- togglePanel();
314
- }
315
- });
316
348
 
317
349
  form?.addEventListener('submit', async (e) => {
318
350
  e.preventDefault();
@@ -325,12 +357,20 @@ const { isAuthenticated } = Astro.props;
325
357
  progressText.textContent = 'Artikel wird generiert...';
326
358
 
327
359
  try {
360
+ // Auto-add page context to notes if on a service page
361
+ let notes = notesInput?.value.trim() || '';
362
+ if (pageContext && !input.toLowerCase().includes(pageContext.toLowerCase())) {
363
+ notes = notes
364
+ ? `Kontext: ${pageContext}. ${notes}`
365
+ : `Artikel im Kontext von ${pageContext}`;
366
+ }
367
+
328
368
  const res = await fetch('/api/articles/create', {
329
369
  method: 'POST',
330
370
  headers: { 'Content-Type': 'application/json' },
331
371
  body: JSON.stringify({
332
372
  input,
333
- notes: notesInput?.value.trim() || undefined,
373
+ notes: notes || undefined,
334
374
  }),
335
375
  });
336
376
 
@@ -2,10 +2,12 @@
2
2
  interface Props {
3
3
  articleId: string;
4
4
  markdown: string;
5
+ title: string;
6
+ description: string;
5
7
  isAuthenticated?: boolean;
6
8
  }
7
9
 
8
- const { articleId, markdown, isAuthenticated } = Astro.props;
10
+ const { articleId, markdown, title, description, isAuthenticated } = Astro.props;
9
11
  ---
10
12
 
11
13
  <div class="inline-editor-wrapper" data-article-id={articleId} data-authenticated={isAuthenticated ? 'true' : 'false'}>
@@ -66,9 +68,20 @@ const { articleId, markdown, isAuthenticated } = Astro.props;
66
68
  <slot />
67
69
  </div>
68
70
 
69
- <!-- Markdown editor (hidden by default) -->
71
+ <!-- Editing form (hidden by default) -->
70
72
  <div class="inline-editor-editing" hidden>
71
- <textarea class="inline-editor-textarea">{markdown}</textarea>
73
+ <div class="inline-editor-field">
74
+ <label class="inline-editor-label">Titel</label>
75
+ <input type="text" class="inline-editor-title-input" value={title} />
76
+ </div>
77
+ <div class="inline-editor-field">
78
+ <label class="inline-editor-label">Beschreibung</label>
79
+ <textarea class="inline-editor-desc-input" rows="2">{description}</textarea>
80
+ </div>
81
+ <div class="inline-editor-field">
82
+ <label class="inline-editor-label">Inhalt (Markdown)</label>
83
+ <textarea class="inline-editor-textarea">{markdown}</textarea>
84
+ </div>
72
85
  </div>
73
86
 
74
87
  <!-- Regenerated preview (hidden by default) -->
@@ -132,6 +145,46 @@ const { articleId, markdown, isAuthenticated } = Astro.props;
132
145
  background: #fecaca !important;
133
146
  }
134
147
 
148
+ .inline-editor-field {
149
+ margin-bottom: 12px;
150
+ }
151
+
152
+ .inline-editor-label {
153
+ display: block;
154
+ font-size: 12px;
155
+ font-weight: 600;
156
+ color: #64748b;
157
+ text-transform: uppercase;
158
+ letter-spacing: 0.05em;
159
+ margin-bottom: 4px;
160
+ }
161
+
162
+ .inline-editor-title-input {
163
+ width: 100%;
164
+ padding: 10px 12px;
165
+ border: 2px solid #3b82f6;
166
+ border-radius: 8px;
167
+ font-size: 1.5rem;
168
+ font-weight: 700;
169
+ color: #0f172a;
170
+ background: #fafbfc;
171
+ box-sizing: border-box;
172
+ }
173
+
174
+ .inline-editor-desc-input {
175
+ width: 100%;
176
+ padding: 10px 12px;
177
+ border: 2px solid #3b82f6;
178
+ border-radius: 8px;
179
+ font-size: 1rem;
180
+ color: #334155;
181
+ background: #fafbfc;
182
+ resize: vertical;
183
+ box-sizing: border-box;
184
+ font-family: inherit;
185
+ line-height: 1.5;
186
+ }
187
+
135
188
  .inline-editor-textarea {
136
189
  width: 100%;
137
190
  min-height: 500px;
@@ -148,6 +201,8 @@ const { articleId, markdown, isAuthenticated } = Astro.props;
148
201
  tab-size: 2;
149
202
  }
150
203
 
204
+ .inline-editor-title-input:focus,
205
+ .inline-editor-desc-input:focus,
151
206
  .inline-editor-textarea:focus {
152
207
  outline: none;
153
208
  border-color: #2563eb;
@@ -180,6 +235,8 @@ const { articleId, markdown, isAuthenticated } = Astro.props;
180
235
  const rendered = el.querySelector('.inline-editor-rendered') as HTMLElement;
181
236
  const editing = el.querySelector('.inline-editor-editing') as HTMLElement;
182
237
  const preview = el.querySelector('.inline-editor-preview') as HTMLElement;
238
+ const titleInput = el.querySelector('.inline-editor-title-input') as HTMLInputElement;
239
+ const descInput = el.querySelector('.inline-editor-desc-input') as HTMLTextAreaElement;
183
240
  const textarea = el.querySelector('.inline-editor-textarea') as HTMLTextAreaElement;
184
241
 
185
242
  type EditorMode = 'view' | 'edit' | 'preview';
@@ -205,7 +262,7 @@ const { articleId, markdown, isAuthenticated } = Astro.props;
205
262
  setMode('view');
206
263
  } else {
207
264
  setMode('edit');
208
- textarea.focus();
265
+ titleInput.focus();
209
266
  }
210
267
  });
211
268
 
@@ -224,6 +281,8 @@ const { articleId, markdown, isAuthenticated } = Astro.props;
224
281
  const body: Record<string, string> = {};
225
282
 
226
283
  if (mode === 'edit') {
284
+ body.title = titleInput.value.trim();
285
+ body.description = descInput.value.trim();
227
286
  body.content = textarea.value;
228
287
  } else if (mode === 'preview' && previewData) {
229
288
  if (previewData.title) body.title = previewData.title;
@@ -283,25 +342,5 @@ const { articleId, markdown, isAuthenticated } = Astro.props;
283
342
  }
284
343
  });
285
344
 
286
- // Tab key inserts spaces in textarea
287
- textarea.addEventListener('keydown', (e) => {
288
- if (e.key === 'Tab') {
289
- e.preventDefault();
290
- const start = textarea.selectionStart;
291
- const end = textarea.selectionEnd;
292
- textarea.value = textarea.value.substring(0, start) + ' ' + textarea.value.substring(end);
293
- textarea.selectionStart = textarea.selectionEnd = start + 2;
294
- }
295
- });
296
-
297
- // Ctrl+S to save in edit mode
298
- textarea.addEventListener('keydown', (e) => {
299
- if ((e.ctrlKey || e.metaKey) && e.key === 's') {
300
- e.preventDefault();
301
- if (mode === 'edit') {
302
- applyBtn.click();
303
- }
304
- }
305
- });
306
345
  });
307
346
  </script>
@@ -1,4 +1,6 @@
1
1
  ---
2
+ import EditorToolbar from '../components/frontend/EditorToolbar.astro';
3
+
2
4
  interface Props {
3
5
  title: string;
4
6
  description?: string;
@@ -1139,6 +1141,7 @@ const isAuthenticated = !!authCookie?.value;
1139
1141
  </div>
1140
1142
  </div>
1141
1143
  </footer>
1144
+ <EditorToolbar isAuthenticated={isAuthenticated} currentPath={currentPath} />
1142
1145
  <script>
1143
1146
  const logoutBtn = document.querySelector('.logout-btn');
1144
1147
  logoutBtn?.addEventListener('click', async () => {
@@ -3,7 +3,7 @@ import Layout from '../../layouts/Layout.astro';
3
3
  import { renderMarkdown } from '../../utils/markdown';
4
4
  import { escapeJsonLd } from '../../utils/sanitize';
5
5
  import HeroImage from '../../components/frontend/HeroImage.astro';
6
- import ArticleHeader from '../../components/frontend/ArticleHeader.astro';
6
+ import InlineEditor from '../../components/frontend/InlineEditor.astro';
7
7
  import SidebarCard from '../../components/frontend/SidebarCard.astro';
8
8
  import BackLink from '../../components/frontend/BackLink.astro';
9
9
  import { ArticleService } from '../../services/ArticleService';
@@ -28,8 +28,12 @@ if (!article) {
28
28
  return Astro.redirect('/');
29
29
  }
30
30
 
31
+ // Fix escaped newlines and remove first H1 (already shown in header)
32
+ const fixedContent = (article.content || '').replace(/\\n/g, '\n');
33
+ const rawContent = fixedContent.replace(/^#\s+.+\n+/, '');
34
+
31
35
  // Render markdown to HTML
32
- const htmlContent = await renderMarkdown(article.content || '');
36
+ const htmlContent = await renderMarkdown(rawContent);
33
37
 
34
38
  // Format the date nicely
35
39
  const formattedDate = article.date.toLocaleDateString('de-DE', {
@@ -68,18 +72,6 @@ const jsonLd = {
68
72
  set:html={escapeJsonLd(JSON.stringify(jsonLd))}
69
73
  />
70
74
  <article class="article-page">
71
- <!-- Article Header -->
72
- <div data-article-id={articleSlug}>
73
- <ArticleHeader
74
- category={article.tags[0]}
75
- date={formattedDate}
76
- datetime={article.date.toISOString()}
77
- lede={article.description}
78
- tags={article.tags}
79
- animate={true}
80
- />
81
- </div>
82
-
83
75
  <!-- Hero Image -->
84
76
  {
85
77
  article.image && (
@@ -91,52 +83,37 @@ const jsonLd = {
91
83
  )
92
84
  }
93
85
 
94
- <!-- Article Body -->
86
+ <!-- Article Content (header + body, all editable via InlineEditor) -->
95
87
  <div class="article-body">
96
- <div class="content-column" data-article-id={articleSlug}>
97
- {
98
- isAuthenticated && (
99
- <div class="content-actions">
100
- <button
101
- class="icon-btn regenerate-text-icon"
102
- type="button"
103
- aria-label="Text neu generieren"
104
- >
105
- <svg
106
- width="18"
107
- height="18"
108
- viewBox="0 0 24 24"
109
- fill="none"
110
- stroke="currentColor"
111
- stroke-width="2"
112
- >
113
- <path d="M23 4v6h-6" />
114
- <path d="M1 20v-6h6" />
115
- <path d="M3.51 9a9 9 0 0 1 14.85-3.36L23 10M1 14l4.64 4.36A9 9 0 0 0 20.49 15" />
116
- </svg>
117
- </button>
118
- <button
119
- class="apply-text-btn"
120
- type="button"
121
- hidden
122
- aria-label="Speichern"
123
- >
124
- <svg
125
- width="18"
126
- height="18"
127
- viewBox="0 0 24 24"
128
- fill="none"
129
- stroke="currentColor"
130
- stroke-width="3"
131
- >
132
- <polyline points="20 6 9 17 4 12" />
133
- </svg>
134
- </button>
88
+ <div class="content-column">
89
+ <InlineEditor
90
+ articleId={articleSlug}
91
+ markdown={rawContent}
92
+ title={article.title}
93
+ description={article.description}
94
+ isAuthenticated={isAuthenticated}
95
+ >
96
+ <header class="article-header" data-animate>
97
+ <div class="article-meta">
98
+ {article.tags[0] && <span class="article-category">{article.tags[0]}</span>}
99
+ <time datetime={article.date.toISOString()}>
100
+ {formattedDate}
101
+ </time>
135
102
  </div>
136
- )
137
- }
138
- <div class="article-content prose" set:html={htmlContent} />
139
- <div class="content-preview prose" hidden></div>
103
+
104
+ <h1>{article.title}</h1>
105
+
106
+ <p class="article-lede">{article.description}</p>
107
+
108
+ {article.tags.length > 0 && (
109
+ <div class="article-tags">
110
+ {article.tags.map((tag: string) => <span class="tag">{tag}</span>)}
111
+ </div>
112
+ )}
113
+ </header>
114
+
115
+ <div class="article-content prose" set:html={htmlContent} />
116
+ </InlineEditor>
140
117
  </div>
141
118
 
142
119
  <!-- Sidebar -->
@@ -157,110 +134,6 @@ const jsonLd = {
157
134
  </Layout>
158
135
 
159
136
  <script>
160
- const contentColumn = document.querySelector(
161
- '.content-column'
162
- ) as HTMLElement;
163
- if (contentColumn) {
164
- const articleId = contentColumn.dataset.articleId;
165
- const regenerateBtn = contentColumn.querySelector(
166
- '.regenerate-text-icon'
167
- ) as HTMLButtonElement;
168
- const contentDiv = contentColumn.querySelector(
169
- '.article-content'
170
- ) as HTMLElement;
171
- const previewDiv = contentColumn.querySelector(
172
- '.content-preview'
173
- ) as HTMLElement;
174
- const applyBtn = contentColumn.querySelector(
175
- '.apply-text-btn'
176
- ) as HTMLButtonElement;
177
-
178
- let previewData: {
179
- title: string;
180
- description: string;
181
- content: string;
182
- } | null = null;
183
-
184
- const buildPreviewDom = (
185
- title: string,
186
- description: string,
187
- content: string
188
- ) => {
189
- const fragment = document.createDocumentFragment();
190
-
191
- const h1 = document.createElement('h1');
192
- h1.textContent = title;
193
- fragment.appendChild(h1);
194
-
195
- const p = document.createElement('p');
196
- const em = document.createElement('em');
197
- em.textContent = description;
198
- p.appendChild(em);
199
- fragment.appendChild(p);
200
-
201
- const body = document.createElement('div');
202
- body.textContent = content.replace(/^#\s+.+\n/, '');
203
- body.style.whiteSpace = 'pre-wrap';
204
- fragment.appendChild(body);
205
-
206
- return fragment;
207
- };
208
-
209
- const showPreview = (fragment: DocumentFragment) => {
210
- previewDiv.replaceChildren(fragment);
211
- contentDiv.hidden = true;
212
- previewDiv.hidden = false;
213
- applyBtn.hidden = false;
214
- regenerateBtn.hidden = true;
215
- };
216
-
217
- const generateText = async () => {
218
- regenerateBtn.disabled = true;
219
- regenerateBtn.classList.add('loading');
220
- try {
221
- const res = await fetch(`/api/articles/${articleId}/regenerate-text`, {
222
- method: 'POST',
223
- });
224
- if (!res.ok) throw new Error('Generation failed');
225
- const data = await res.json();
226
- previewData = {
227
- title: data.title,
228
- description: data.description,
229
- content: data.content,
230
- };
231
- showPreview(
232
- buildPreviewDom(data.title, data.description, data.content)
233
- );
234
- } catch {
235
- alert('Text-Generierung fehlgeschlagen');
236
- regenerateBtn.disabled = false;
237
- regenerateBtn.classList.remove('loading');
238
- }
239
- };
240
-
241
- const applyChanges = async () => {
242
- if (!previewData) return;
243
- applyBtn.disabled = true;
244
- applyBtn.classList.add('loading');
245
- try {
246
- const res = await fetch(`/api/articles/${articleId}/apply`, {
247
- method: 'POST',
248
- headers: { 'Content-Type': 'application/json' },
249
- body: JSON.stringify(previewData),
250
- });
251
- if (!res.ok) throw new Error('Save failed');
252
- window.location.reload();
253
- } catch {
254
- alert('Speichern fehlgeschlagen');
255
- applyBtn.disabled = false;
256
- applyBtn.classList.remove('loading');
257
- }
258
- };
259
-
260
- regenerateBtn?.addEventListener('click', generateText);
261
- applyBtn?.addEventListener('click', applyChanges);
262
- }
263
-
264
137
  document.querySelectorAll('.prose pre').forEach((pre) => {
265
138
  pre.setAttribute('tabindex', '0');
266
139
  pre.setAttribute('role', 'region');
@@ -279,50 +152,57 @@ const jsonLd = {
279
152
  padding: 0 var(--gutter);
280
153
  }
281
154
 
282
- .article-body {
283
- display: grid;
284
- grid-template-columns: minmax(0, 1fr) 280px;
285
- gap: var(--space-16);
286
- max-width: 1100px;
287
- }
288
-
289
- .content-column {
290
- min-width: 0;
291
- overflow: hidden;
155
+ .article-header {
156
+ margin-bottom: var(--space-8);
292
157
  }
293
158
 
294
- .content-actions {
159
+ .article-meta {
295
160
  display: flex;
296
161
  align-items: center;
297
- gap: var(--space-2);
162
+ gap: var(--space-3);
298
163
  margin-bottom: var(--space-4);
164
+ font-size: var(--text-sm);
165
+ color: var(--color-text-muted);
299
166
  }
300
167
 
301
- .apply-text-btn {
302
- display: flex;
303
- align-items: center;
304
- justify-content: center;
305
- width: 36px;
306
- height: 36px;
307
- background: var(--color-success, #4ade80);
308
- border: none;
309
- border-radius: var(--radius-md);
310
- color: #000;
311
- cursor: pointer;
312
- transition: background 0.2s ease;
168
+ .article-category {
169
+ text-transform: uppercase;
170
+ letter-spacing: 0.05em;
171
+ font-weight: 600;
172
+ color: var(--color-accent);
173
+ }
174
+
175
+ .article-header h1 {
176
+ font-size: var(--text-4xl);
177
+ font-weight: 800;
178
+ line-height: 1.15;
179
+ color: var(--color-text);
180
+ margin-bottom: var(--space-4);
313
181
  }
314
182
 
315
- .apply-text-btn:hover {
316
- background: #22c55e;
183
+ .article-lede {
184
+ font-size: var(--text-lg);
185
+ color: var(--color-text-muted);
186
+ line-height: 1.6;
187
+ margin-bottom: var(--space-6);
317
188
  }
318
189
 
319
- .apply-text-btn:disabled {
320
- opacity: 0.6;
321
- cursor: not-allowed;
190
+ .article-tags {
191
+ display: flex;
192
+ flex-wrap: wrap;
193
+ gap: var(--space-2);
322
194
  }
323
195
 
324
- .apply-text-btn.loading svg {
325
- animation: spin 1s linear infinite;
196
+ .article-body {
197
+ display: grid;
198
+ grid-template-columns: minmax(0, 1fr) 280px;
199
+ gap: var(--space-16);
200
+ max-width: 1100px;
201
+ }
202
+
203
+ .content-column {
204
+ min-width: 0;
205
+ overflow: hidden;
326
206
  }
327
207
 
328
208
  .article-sidebar {
package/update.md CHANGED
@@ -1,3 +1,43 @@
1
+ # v1.1.1
2
+
3
+ ## Enhancement: Inline editing for title + description, context-aware toolbar
4
+
5
+ ### InlineEditor: title and description editing
6
+ - New `title` and `description` props (required)
7
+ - Edit mode now shows three fields: title input, description textarea, markdown textarea
8
+ - All three saved in one apply call to `/api/articles/{id}/apply`
9
+ - Title field gets focus first when entering edit mode
10
+ - Ctrl+S works from any field (not just markdown textarea)
11
+
12
+ ### EditorToolbar: page context awareness
13
+ - New `currentPath` prop — detects service pages and extracts topic
14
+ - On `/services/gleitschleifen`: shows "Kontext: Gleitschleifen" badge in panel
15
+ - Placeholder adapts: "z.B. Gleitschleifen Kosten, Gleitschleifen Vorteile"
16
+ - Context auto-added to generation notes when topic doesn't already include it
17
+ - Article generated from a service page gets that service as context in the prompt
18
+
19
+ ### Integration update
20
+
21
+ InlineEditor now requires `title` and `description`:
22
+ ```astro
23
+ <InlineEditor
24
+ articleId={articleSlug}
25
+ markdown={rawContent}
26
+ title={article.title}
27
+ description={article.description}
28
+ isAuthenticated={isAuthenticated}
29
+ >
30
+ <!-- header + content as slot -->
31
+ </InlineEditor>
32
+ ```
33
+
34
+ EditorToolbar now accepts `currentPath`:
35
+ ```astro
36
+ <EditorToolbar isAuthenticated={isAuthenticated} currentPath={Astro.url.pathname} />
37
+ ```
38
+
39
+ ---
40
+
1
41
  # v1.1.0
2
42
 
3
43
  ## Feature: Frontend editing — EditorToolbar, InlineEditor, create endpoint