diff --git a/src/i18n/locales/de.ts b/src/i18n/locales/de.ts
index 8dedb3ef..56580dd8 100644
--- a/src/i18n/locales/de.ts
+++ b/src/i18n/locales/de.ts
@@ -728,6 +728,19 @@ export default {
listImportATagFailed: 'Adress-Tag konnte nicht aufgelöst werden: {{preview}}…',
listImportEventNotFound: 'Kein Event zu dieser Referenz gefunden.',
'REQ tag filters': 'REQ-Tag-Filter',
+ spellFormTagFiltersLabel: 'Tag-Filter auf passenden Events',
+ spellCreateIntro:
+ 'Zaubersprüche sind gespeicherte Relay-Filter (NIP-A7). Der Abschnitt „Abfrage“ ist die eigentliche Definition; der gestrichelte Kasten unten nur für Namen, Beschreibung und Katalog-Labels. Beim Ausführen: $me für deinen Pubkey, $contacts für deine Follow-Liste.',
+ spellFormSectionQueryTitle: 'Abfrage (Spell-Definition)',
+ spellFormSectionQueryHint:
+ 'Dieser Block ist die eigentliche Definition: Er wird zum Nostr-REQ-/COUNT-Filter (Kinds, Autoren, Zeitraum, Tag-Filter auf passenden Events, Relays usw.).',
+ spellFormSectionMetadataTitle: 'Anzeige & Beschriftung (optional)',
+ spellFormSectionMetadataBadge: 'Gehört nicht zur Abfrage',
+ spellFormSectionMetadataHint:
+ 'Name, Beschreibung und Themen-Labels dienen nur der Darstellung und in Zauberspruch-Listen. Sie werden beim Abrufen von Events nicht verwendet.',
+ spellFormCatalogTopicsLabel: 'Themen-Labels auf dem Zauberspruch (t-Tags)',
+ spellTopicsMetadataHint:
+ 'Ein Thema pro Zeile. Um Notes nach Thema zu filtern, nutze oben im Block „Abfrage“ die REQ-Tag-Filter (Buchstabe „t“).',
spellTagFiltersHint:
'Optionale Filter auf abonnierte Events (NIP-01 Ein-Buchstaben-Tags). Beispiel: Buchstabe „t“, Werte „bitcoin“.',
spellTagFiltersEmpty:
diff --git a/src/i18n/locales/en.ts b/src/i18n/locales/en.ts
index 37e87ae2..5f4b277c 100644
--- a/src/i18n/locales/en.ts
+++ b/src/i18n/locales/en.ts
@@ -763,6 +763,19 @@ export default {
listImportATagFailed: 'Failed to resolve address tag: {{preview}}…',
listImportEventNotFound: 'No event found for that reference.',
'REQ tag filters': 'REQ tag filters',
+ spellFormTagFiltersLabel: 'Tag filters on matching events',
+ spellCreateIntro:
+ 'Spells are saved relay filters (NIP-A7). The “Spell query” section is the real definition; the dashed box at the bottom is only for names, descriptions, and catalog labels. Use $me for your pubkey and $contacts for your follow list when executing.',
+ spellFormSectionQueryTitle: 'Spell query',
+ spellFormSectionQueryHint:
+ 'This block is the actual spell definition: it becomes the Nostr REQ/COUNT filter (kinds, authors, time range, tag filters on matching events, relays, etc.).',
+ spellFormSectionMetadataTitle: 'Listing & labels (optional)',
+ spellFormSectionMetadataBadge: 'Not part of the query',
+ spellFormSectionMetadataHint:
+ 'Name, description, and topic labels are only for display and spell pickers. They are not used when the spell fetches events.',
+ spellFormCatalogTopicsLabel: 'Topic labels on this spell (t tags)',
+ spellTopicsMetadataHint:
+ 'One topic per row. To filter which notes you see, use “REQ tag filters” in the spell query above (letter “t”).',
spellTagFiltersHint:
'Optional filters on subscribed events (NIP-01 single-letter tags). Example: letter “t”, values “bitcoin”.',
spellTagFiltersEmpty: 'No tag filters yet. Add rows below or apply an event reference above.',
diff --git a/src/pages/primary/SpellsPage/CreateSpellDialog.tsx b/src/pages/primary/SpellsPage/CreateSpellDialog.tsx
index 179e3195..8394d98e 100644
--- a/src/pages/primary/SpellsPage/CreateSpellDialog.tsx
+++ b/src/pages/primary/SpellsPage/CreateSpellDialog.tsx
@@ -23,10 +23,10 @@ import { showPublishingError, showSimplePublishSuccess } from '@/lib/publishing-
import client from '@/services/client.service'
import indexedDb from '@/services/indexed-db.service'
import { getRelaysForSpellCatalogSync } from '@/services/spell.service'
-import { Minus, Plus, X } from 'lucide-react'
+import { Info, Minus, Plus, X } from 'lucide-react'
import { useTranslation } from 'react-i18next'
import type { Event as NostrEvent } from 'nostr-tools'
-import { useCallback, useEffect, useRef, useState } from 'react'
+import { useCallback, useEffect, useRef, useState, type ReactNode } from 'react'
import logger from '@/lib/logger'
/** Arrow keys should control the control, not the dialog scroll */
@@ -140,6 +140,44 @@ function DynamicStringListField({
)
}
+/** Bottom-of-form panel: name, description, catalog topics — not part of NIP-A7 REQ filter. */
+function SpellMetadataSection({
+ title,
+ badge,
+ hint,
+ children
+}: {
+ title: string
+ badge: string
+ hint: string
+ children: ReactNode
+}) {
+ return (
+
+
+
+
+
+ {title}
+
+
+ {badge}
+
+
+
{hint}
+
+
{children}
+
+ )
+}
+
function TagFiltersEditor({
tagFilters,
onChange
@@ -156,7 +194,7 @@ function TagFiltersEditor({
}
return (
-
+
{t('spellTagFiltersHint')}
{tagFilters.length === 0 ? (
{t('spellTagFiltersEmpty')}
@@ -405,9 +443,7 @@ export default function CreateSpellDialog({
{spellToClone
? t('Clone spell intro')
- : t(
- 'Spells are saved relay filters (NIP-A7). Fill in the filter fields below. Use $me for your pubkey and $contacts for your follow list when executing.'
- )}
+ : t('spellCreateIntro')}