nca-ai-cms-astro-plugin 1.1.1 → 1.1.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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "nca-ai-cms-astro-plugin",
3
- "version": "1.1.1",
3
+ "version": "1.1.2",
4
4
  "type": "module",
5
5
  "exports": {
6
6
  ".": "./src/index.ts",
@@ -60,6 +60,18 @@ const { articleId, markdown, title, description, isAuthenticated } = Astro.props
60
60
  <line x1="6" y1="6" x2="18" y2="18" />
61
61
  </svg>
62
62
  </button>
63
+ <span class="inline-toolbar-spacer"></span>
64
+ <button
65
+ type="button"
66
+ class="inline-delete-btn"
67
+ aria-label="Artikel löschen"
68
+ title="Artikel löschen"
69
+ >
70
+ <svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
71
+ <polyline points="3 6 5 6 21 6" />
72
+ <path d="M19 6v14a2 2 0 0 1-2 2H7a2 2 0 0 1-2-2V6m3 0V4a2 2 0 0 1 2-2h4a2 2 0 0 1 2 2v2" />
73
+ </svg>
74
+ </button>
63
75
  </div>
64
76
  )}
65
77
 
@@ -145,6 +157,22 @@ const { articleId, markdown, title, description, isAuthenticated } = Astro.props
145
157
  background: #fecaca !important;
146
158
  }
147
159
 
160
+ .inline-toolbar-spacer {
161
+ flex: 1;
162
+ }
163
+
164
+ .inline-delete-btn {
165
+ background: transparent !important;
166
+ color: #94a3b8 !important;
167
+ border-color: transparent !important;
168
+ }
169
+
170
+ .inline-delete-btn:hover {
171
+ background: #fef2f2 !important;
172
+ color: #dc2626 !important;
173
+ border-color: #fecaca !important;
174
+ }
175
+
148
176
  .inline-editor-field {
149
177
  margin-bottom: 12px;
150
178
  }
@@ -232,6 +260,7 @@ const { articleId, markdown, title, description, isAuthenticated } = Astro.props
232
260
  const regenBtn = el.querySelector('.inline-regenerate-btn') as HTMLButtonElement;
233
261
  const applyBtn = el.querySelector('.inline-apply-btn') as HTMLButtonElement;
234
262
  const cancelBtn = el.querySelector('.inline-cancel-btn') as HTMLButtonElement;
263
+ const deleteBtn = el.querySelector('.inline-delete-btn') as HTMLButtonElement;
235
264
  const rendered = el.querySelector('.inline-editor-rendered') as HTMLElement;
236
265
  const editing = el.querySelector('.inline-editor-editing') as HTMLElement;
237
266
  const preview = el.querySelector('.inline-editor-preview') as HTMLElement;
@@ -254,6 +283,7 @@ const { articleId, markdown, title, description, isAuthenticated } = Astro.props
254
283
  regenBtn.hidden = mode !== 'view';
255
284
  applyBtn.hidden = mode === 'view';
256
285
  cancelBtn.hidden = mode === 'view';
286
+ deleteBtn.hidden = mode !== 'view';
257
287
  };
258
288
 
259
289
  // Edit mode
@@ -342,5 +372,25 @@ const { articleId, markdown, title, description, isAuthenticated } = Astro.props
342
372
  }
343
373
  });
344
374
 
375
+ // Delete article
376
+ deleteBtn?.addEventListener('click', async () => {
377
+ if (!confirm('Artikel wirklich löschen? Dies kann nicht rückgängig gemacht werden.')) return;
378
+ deleteBtn.disabled = true;
379
+
380
+ try {
381
+ deleteBtn.classList.add('loading');
382
+ const res = await fetch(`/api/articles/${articleId}`, {
383
+ method: 'DELETE',
384
+ credentials: 'same-origin',
385
+ });
386
+ if (!res.ok) throw new Error('Löschen fehlgeschlagen');
387
+ window.location.href = '/';
388
+ } catch {
389
+ alert('Artikel konnte nicht gelöscht werden');
390
+ deleteBtn.disabled = false;
391
+ deleteBtn.classList.remove('loading');
392
+ }
393
+ });
394
+
345
395
  });
346
396
  </script>
@@ -4,7 +4,6 @@ import * as fs from 'fs/promises';
4
4
  import * as path from 'path';
5
5
  import { db, SiteSettings, eq } from 'astro:db';
6
6
  import Layout from '../layouts/Layout.astro';
7
- import DeleteAction from '../components/frontend/DeleteAction.astro';
8
7
  import { ArticleService } from '../services/ArticleService';
9
8
  import { escapeJsonLd } from '../utils/sanitize';
10
9
 
@@ -128,14 +127,6 @@ const homeJsonLd = {
128
127
  href={`/articles/${featuredArticle.articleId}`}
129
128
  class="featured-card"
130
129
  >
131
- {isAuthenticated && (
132
- <DeleteAction
133
- articleId={
134
- featuredArticle.articleId.split('/').pop() ||
135
- featuredArticle.articleId
136
- }
137
- />
138
- )}
139
130
  <div class="featured-card-image img-zoom">
140
131
  {featuredArticle.image ? (
141
132
  <Image
@@ -198,14 +189,6 @@ const homeJsonLd = {
198
189
  { 'article-card--wide': index % 5 === 0 },
199
190
  ]}
200
191
  >
201
- {isAuthenticated && (
202
- <DeleteAction
203
- articleId={
204
- article.articleId.split('/').pop() ||
205
- article.articleId
206
- }
207
- />
208
- )}
209
192
  <div class="article-card-image img-zoom">
210
193
  {article.image ? (
211
194
  <Image
package/update.md CHANGED
@@ -1,3 +1,14 @@
1
+ # v1.1.2
2
+
3
+ ## Feature: Delete button in InlineEditor
4
+
5
+ - Trash icon in the toolbar, right-aligned, subtle gray until hover (then red)
6
+ - Confirm dialog before deleting: "Artikel wirklich löschen?"
7
+ - Calls `DELETE /api/articles/{id}` then redirects to homepage
8
+ - Only visible when authenticated
9
+
10
+ ---
11
+
1
12
  # v1.1.1
2
13
 
3
14
  ## Enhancement: Inline editing for title + description, context-aware toolbar
@@ -1,144 +0,0 @@
1
- ---
2
- interface Props {
3
- articleId: string;
4
- }
5
- const { articleId } = Astro.props;
6
- ---
7
-
8
- <div class="delete-action" data-article-id={articleId}>
9
- <button class="delete-icon" aria-label="Artikel löschen" type="button">
10
- <svg
11
- width="18"
12
- height="18"
13
- viewBox="0 0 24 24"
14
- fill="none"
15
- stroke="currentColor"
16
- stroke-width="2"
17
- stroke-linecap="round"
18
- stroke-linejoin="round"
19
- >
20
- <polyline points="3 6 5 6 21 6"></polyline>
21
- <path
22
- d="M19 6v14a2 2 0 0 1-2 2H7a2 2 0 0 1-2-2V6m3 0V4a2 2 0 0 1 2-2h4a2 2 0 0 1 2 2v2"
23
- ></path>
24
- <line x1="10" y1="11" x2="10" y2="17"></line>
25
- <line x1="14" y1="11" x2="14" y2="17"></line>
26
- </svg>
27
- </button>
28
- <button class="confirm-yes" type="button" hidden>Ja</button>
29
- </div>
30
-
31
- <script>
32
- document.querySelectorAll('.delete-action').forEach((container) => {
33
- const articleId = (container as HTMLElement).dataset.articleId;
34
- const icon = container.querySelector('.delete-icon') as HTMLButtonElement;
35
- const confirmBtn = container.querySelector(
36
- '.confirm-yes'
37
- ) as HTMLButtonElement;
38
-
39
- const showConfirm = () => {
40
- icon.hidden = true;
41
- confirmBtn.hidden = false;
42
- };
43
-
44
- const resetState = () => {
45
- confirmBtn.hidden = true;
46
- confirmBtn.disabled = false;
47
- confirmBtn.textContent = 'Ja';
48
- icon.hidden = false;
49
- };
50
-
51
- const removeCard = () => {
52
- const card = container.closest('.article-card, .featured-card');
53
- card ? card.remove() : window.location.reload();
54
- };
55
-
56
- const deleteArticle = async () => {
57
- confirmBtn.disabled = true;
58
- confirmBtn.textContent = '...';
59
-
60
- try {
61
- const response = await fetch(`/api/articles/${articleId}`, {
62
- method: 'DELETE',
63
- credentials: 'same-origin',
64
- });
65
- response.ok
66
- ? removeCard()
67
- : (alert('Löschen fehlgeschlagen'), resetState());
68
- } catch {
69
- alert('Löschen fehlgeschlagen');
70
- resetState();
71
- }
72
- };
73
-
74
- icon?.addEventListener('click', (e) => {
75
- e.preventDefault();
76
- e.stopPropagation();
77
- showConfirm();
78
- });
79
-
80
- confirmBtn?.addEventListener('click', (e) => {
81
- e.preventDefault();
82
- e.stopPropagation();
83
- deleteArticle();
84
- });
85
- });
86
- </script>
87
-
88
- <style>
89
- .delete-action {
90
- position: absolute;
91
- top: var(--space-3, 0.75rem);
92
- right: var(--space-3, 0.75rem);
93
- z-index: 10;
94
- }
95
-
96
- .delete-icon {
97
- display: flex;
98
- align-items: center;
99
- justify-content: center;
100
- width: 36px;
101
- height: 36px;
102
- background: var(--color-surface);
103
- border: 1px solid var(--color-border);
104
- border-radius: var(--radius-md);
105
- color: var(--color-text-muted);
106
- cursor: pointer;
107
- transition:
108
- color 0.2s ease,
109
- background 0.2s ease,
110
- border-color 0.2s ease;
111
- }
112
-
113
- .delete-icon:hover {
114
- color: var(--color-error);
115
- background: var(--color-error-muted);
116
- border-color: var(--color-error);
117
- }
118
-
119
- .delete-icon:disabled {
120
- opacity: 0.5;
121
- cursor: not-allowed;
122
- }
123
-
124
- .confirm-yes {
125
- padding: var(--space-1, 0.25rem) var(--space-3, 0.75rem);
126
- font-family: var(--font-ui);
127
- font-size: var(--text-sm, 0.875rem);
128
- font-weight: 600;
129
- border: none;
130
- border-radius: var(--radius-sm, 4px);
131
- cursor: pointer;
132
- background: var(--color-error, #f87171);
133
- color: white;
134
- }
135
-
136
- .confirm-yes:hover {
137
- background: #ef4444;
138
- }
139
-
140
- .confirm-yes:disabled {
141
- opacity: 0.6;
142
- cursor: not-allowed;
143
- }
144
- </style>