Emojis zum Anklicken, und Wuensche als Forums-Beitraege mit Tags
Deploy / check (push) Has been cancelled
Deploy / deploy (push) Has been cancelled

Ueberall, wo ein Emoji nach Discord geht — Rollen-Menues, Ticket-Anliegen,
Wunsch-Bereiche, Portal-Kacheln — stand ein leeres Textfeld, in das man mit
Win+. hineintippen musste. Jetzt sitzt daneben ein Knopf mit einer Tafel:
sieben Gruppen, deutsche Suchbegriffe ("auto", "geld", "warnung"), ein Klick
schreibt ins Feld. Das Feld bleibt daneben stehen, denn Server-Emojis
(<:name:123>) kennt nur Discord.

Bewusst eine eigene Liste statt einer Bibliothek: die vollstaendige
Unicode-Tabelle waere ein halbes Megabyte fuer eine Handvoll Symbole, und die
Suchbegriffe duerfen deutsch sein.

## Forum-Tags

Ist der Voting-Kanal ein Forum, wird jeder Wunsch jetzt ein Forums-Beitrag
statt Nachricht-plus-Thread — und bekommt Tags fuer Bereich und Stand. Damit
laesst sich auch in Discord filtern, wofuer Tags ja da sind. Beim Wechsel des
Stands zieht das Tag mit: der alte fliegt raus, der neue kommt rein, der
Bereich bleibt stehen.

Zugeordnet wird ueber den Namen. Wer im Forum ein Tag "Fahrzeuge" anlegt,
bekommt es automatisch gesetzt; wer keines anlegt, verliert nichts. Bewusst
keine ID-Zuordnung im Panel — das waere eine zweite Liste, die man pflegen
muss und die beim ersten Umbenennen auseinanderlaeuft.

Dabei aufgefallen und mitgefixt: im Forum liegt die Startnachricht im Beitrag
selbst und nicht im Kanal. Der Status-Aktualisierer hat sie vorher im Kanal
gesucht und nicht gefunden — die Begruendung waere im Forum also nie im Post
gelandet. Und der Titel wird jetzt nur um den Stand ergaenzt statt
ueberschrieben, damit "🚗 Fahrzeuge" stehen bleibt.

Geprueft: tagsFuer gegen 20 Faelle — kein Forum, Medien-Kanal, fehlende Tags,
Gross/Kleinschreibung, Deckel bei fuenf (mehr nimmt Discord nicht), und alle
fuenf Staende einzeln. Im Browser die Emoji-Tafel an allen vier Stellen:
Suche, Escape, Klick daneben, Leeren, Uebernehmen.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
2026-08-01 23:45:18 +02:00
co-authored by Claude Opus 5
parent edf8fa14c5
commit cc7a51f02e
7 changed files with 366 additions and 26 deletions
+27 -7
View File
@@ -12,6 +12,7 @@ import { moduleIcon } from '../module-icons.jsx';
import ModulePage from '../components/ModulePage.jsx';
import UptimeTrack from '../components/UptimeTrack.jsx';
import Dialog from '../components/Dialog.jsx';
import EmojiPick from '../components/EmojiPick.jsx';
import { findSettings, SETTING_INDEX } from '../setting-index.js';
import { Markdown } from '../markdown.jsx';
@@ -1878,6 +1879,14 @@ export default function Settings({ me }) {
der Aufruf-Post in Discord fragt beim Einreichen nach dem Bereich. Nach dem
Ändern <strong>/wunsch-setup</strong> neu ausführen.
</p>
<p className="section-intro">
Ist der Voting-Kanal ein <strong>Forum</strong>, wird jeder Wunsch ein
Forums-Beitrag und bekommt Tags. Leg dort Tags mit denselben Namen an wie hier
die Bereiche, dazu <em>Wird geprüft</em>, <em>Geplant</em>, <em>In Arbeit</em>,
<em>Umgesetzt</em> und <em>Nicht geplant</em> dann kann man auch in Discord
danach filtern, und der Stand zieht automatisch mit. Fehlt ein Tag, bleibt es
einfach ohne.
</p>
{bereiche.length === 0 && <p className="notice">Noch keine Bereiche.</p>}
@@ -1906,10 +1915,10 @@ export default function Settings({ me }) {
)}
<div className="field-row">
<input
type="text" maxLength={32} placeholder="🚗" style={{ maxWidth: '5rem' }}
<EmojiPick
value={bereichDraft.emoji}
onChange={(e) => setBereichDraft({ ...bereichDraft, emoji: e.target.value })}
onChange={(v) => setBereichDraft({ ...bereichDraft, emoji: v })}
placeholder="🚗"
/>
<input
type="text" maxLength={40} placeholder="Name, z. B. Fahrzeuge"
@@ -2101,7 +2110,11 @@ export default function Settings({ me }) {
<label>Rollen <span className="field-hint">Emoji optional (auch Custom als &lt;:name:id&gt;), Label = Button-Text</span></label>
{menuDraft.entries.map((entry, i) => (
<div className="rr-row" key={i}>
<input type="text" className="rr-emoji" placeholder="🎮" value={entry.emoji} onChange={(e) => setMenuEntry(i, { emoji: e.target.value })} />
<EmojiPick
value={entry.emoji}
onChange={(v) => setMenuEntry(i, { emoji: v })}
placeholder="🎮"
/>
<input type="text" placeholder="Button-Label, z. B. FiveM" value={entry.label} onChange={(e) => setMenuEntry(i, { label: e.target.value })} />
<PickSelect
items={roleItems}
@@ -2306,8 +2319,11 @@ export default function Settings({ me }) {
</div>
<div className="field">
<label>Emoji <span className="field-hint">ein Zeichen oder ein Server-Emoji wie &lt;:name:123&gt; — unpassendes wird weggelassen</span></label>
<input type="text" maxLength={32} placeholder="🐛" value={anliegenDraft.emoji}
onChange={(e) => setAnliegenDraft({ ...anliegenDraft, emoji: e.target.value })} />
<EmojiPick
value={anliegenDraft.emoji}
onChange={(v) => setAnliegenDraft({ ...anliegenDraft, emoji: v })}
placeholder="🐛"
/>
</div>
<div className="field">
<label>Kurzbeschreibung <span className="field-hint">graue Zeile unter dem Namen im Menü — höchstens 100 Zeichen</span></label>
@@ -2896,7 +2912,11 @@ export default function Settings({ me }) {
<div className="field">
<label>{serviceDraft.id ? `Dienst #${serviceDraft.id} bearbeiten` : 'Neuer Dienst'}</label>
<div className="field-row">
<input type="text" style={{ flex: 'none', width: '4rem' }} placeholder="🗂️" value={serviceDraft.icon} onChange={(e) => setServiceDraft({ ...serviceDraft, icon: e.target.value })} />
<EmojiPick
value={serviceDraft.icon}
onChange={(v) => setServiceDraft({ ...serviceDraft, icon: v })}
placeholder="🗂️"
/>
<input type="text" style={{ flex: 'none', width: '10rem' }} placeholder="Kanban" value={serviceDraft.name} onChange={(e) => setServiceDraft({ ...serviceDraft, name: e.target.value })} />
<input type="text" placeholder="https://kanban.d4rkst3r.de" value={serviceDraft.url} onChange={(e) => setServiceDraft({ ...serviceDraft, url: e.target.value })} />
<input type="number" style={{ flex: 'none', width: '5rem' }} placeholder="Pos." value={serviceDraft.sort} onChange={(e) => setServiceDraft({ ...serviceDraft, sort: e.target.value })} />