Wichtige Funktionen direkt in der Seitenleiste
Deploy / check (push) Has been cancelled
Deploy / deploy (push) Has been cancelled

Nach dem Umbau lagen alle Funktionen hinter dem Raster — für die vier, fünf,
die man dauernd anfasst, ist das ein Umweg zu viel.

Oben in der Seitenleiste steht jetzt „Meine Funktionen": ein Klick öffnet
die Seite direkt. Welche dort stehen, entscheidet der Stern auf der
Modul-Karte oder auf der Seite selbst.

Bewusst nicht alle 35: Deckel bei acht, sonst ist der Gewinn gegenüber dem
Raster wieder weg. Der Standard ist eine Vermutung (Devlogs, Willkommen,
Tickets, Starboard, Galerie) und ausdrücklich zum Ändern gedacht.

Die Auswahl liegt als Einstellung in der Datenbank, nicht im Browser — sie
gilt damit auf jedem Gerät und fürs ganze Team. Eine geleerte Auswahl wird
als solche gespeichert, sonst käme beim nächsten Laden der Standard zurück.

Der Stern ist ungeheftet nur angedeutet und wird erst beim Überfahren
deutlich — 35 Karten mit vollen Sternen sähen aus wie ein Sternenhimmel.

Nebenbei: bei geöffneter Modul-Seite war sowohl „Module" als auch die
Funktion in der Leiste hervorgehoben. Jetzt nur noch die Funktion.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
2026-07-31 22:08:42 +02:00
co-authored by Claude Fable 5
parent de4e812896
commit c026b2a603
6 changed files with 140 additions and 6 deletions
+57 -2
View File
@@ -6,7 +6,7 @@ import {
IconApplications, IconComposer, IconServer, IconSystem, IconApi, IconTeam,
IconLock, IconBot, IconUpload, IconChevronDown, IconKey, IconPages, IconX,
IconHome as IconLayers, IconWarning, IconCheck, IconMessage, IconRefresh,
IconSearch, IconSystem as IconTune,
IconSearch, IconSystem as IconTune, IconStar,
} from '../icons.jsx';
import { moduleIcon } from '../module-icons.jsx';
import ModulePage from '../components/ModulePage.jsx';
@@ -315,6 +315,9 @@ export default function Settings({ me }) {
window.history.replaceState(null, '', id ? `#module/${id}` : '#module');
};
const [creating, setCreating] = useState(null); // Einstellung, die gerade angelegt wird
// Funktionen, die in der Seitenleiste stehen
const [favorites, setFavorites] = useState([]);
const [maxFavorites, setMaxFavorites] = useState(8);
// Grundgerüst-Assistent
const [plan, setPlan] = useState(null); // Vorschau, null = zu
const [setupRunning, setSetupRunning] = useState(false);
@@ -425,6 +428,8 @@ export default function Settings({ me }) {
apiGet('/api/modules').then((d) => {
setModules(d.modules);
setModuleGroups(d.groups);
setFavorites(d.favorites ?? []);
setMaxFavorites(d.maxFavorites ?? 8);
}).catch(() => {});
apiGet('/api/texts').then((d) => {
setTemplates(d.templates);
@@ -526,6 +531,21 @@ export default function Settings({ me }) {
}
}
/** Funktion in der Seitenleiste an- oder abheften */
async function toggleFavorite(id) {
const dabei = favorites.includes(id);
const neu = dabei ? favorites.filter((f) => f !== id) : [...favorites, id];
const vorher = favorites;
setFavorites(neu); // sofort umschalten
try {
const res = await apiPut('/api/module-favorites', { ids: neu });
setFavorites(res.favorites);
} catch (error) {
setFavorites(vorher); // bei Ablehnung zurück
flash(`${error.body?.error ?? 'Fehlgeschlagen'}`);
}
}
/** Vorschau holen: was würde der Assistent anlegen? */
async function loadPlan() {
try {
@@ -2387,6 +2407,8 @@ export default function Settings({ me }) {
flash={flash}
goTab={setTab}
reloadSettings={reloadSettings}
favorites={favorites}
onToggleFavorite={toggleFavorite}
/>
) : (
<div className="settings-section">
@@ -2431,6 +2453,15 @@ export default function Settings({ me }) {
<span className="mod-group">{groupLabel(m.group)}</span>
</span>
</button>
<button
className={`mod-fav${favorites.includes(m.id) ? ' on' : ''}`}
title={favorites.includes(m.id)
? 'Aus der Seitenleiste nehmen'
: 'In die Seitenleiste heften'}
onClick={() => toggleFavorite(m.id)}
>
<IconStar size={15} />
</button>
<button
className={`mod-switch${m.enabled ? ' on' : ''}`}
title={m.enabled ? 'Ausschalten' : 'Einschalten'}
@@ -2907,6 +2938,30 @@ export default function Settings({ me }) {
<p className="settings-nav-empty">Nichts gefunden.</p>
)}
{/* Angeheftete Funktionen — direkt erreichbar, ohne Umweg
übers Raster. Bei aktiver Suche ausgeblendet, dort
zählen Treffer. */}
{!query && canTab('module') && favorites.length > 0 && (
<div className="settings-nav-group">
<span className="settings-nav-label">Meine Funktionen</span>
{favorites.map((id) => {
const m = modules.find((x) => x.id === id);
if (!m) return null;
const Icon = moduleIcon(id);
return (
<button
key={id}
className={`settings-nav-item ${openModule === id ? 'active' : ''}`}
onClick={() => { setTabState('module'); setOpenModule(id); }}
>
<span className="settings-nav-icon"><Icon /></span>
{m.name}
</button>
);
})}
</div>
)}
{TAB_SECTIONS.map((section) => {
const items = foundTabs.filter((t) => t.section === section.id);
if (items.length === 0) return null;
@@ -2916,7 +2971,7 @@ export default function Settings({ me }) {
{items.map((t) => (
<button
key={t.id}
className={`settings-nav-item ${tab === t.id ? 'active' : ''}`}
className={`settings-nav-item ${tab === t.id && !(t.id === 'module' && openModule) ? 'active' : ''}`}
onClick={() => setTab(t.id)}
>
<span className="settings-nav-icon"><t.Icon /></span>