Enhance Exercise List Page with AI Assistant Toggle and UI Improvements
All checks were successful
Deploy Development / deploy (push) Successful in 43s
Test Suite / pytest-backend (push) Successful in 40s
Test Suite / lint-backend (push) Successful in 0s
Test Suite / build-frontend (push) Successful in 16s
Test Suite / k6 /health Baseline (push) Successful in 34s
Test Suite / playwright-tests (push) Successful in 1m13s
Test Suite / pytest-backend (pull_request) Successful in 37s
Test Suite / lint-backend (pull_request) Successful in 1s
Test Suite / build-frontend (pull_request) Successful in 12s
Test Suite / k6 /health Baseline (pull_request) Successful in 33s
Test Suite / playwright-tests (pull_request) Successful in 1m17s

- Introduced a new AI assistant toggle in the Exercise List Page header, allowing users to enable quick exercise creation via AI suggestions.
- Updated the ExerciseListSearchBar component to remove deprecated AI quick create functionality, streamlining the interface.
- Enhanced CSS styles for the AI assistant toggle, improving visual feedback and user interaction.
- Improved overall layout and spacing in the exercises page for better usability.
This commit is contained in:
Lars 2026-05-22 19:44:15 +02:00
parent c816e50c68
commit 9d880e2346
3 changed files with 84 additions and 32 deletions

View File

@ -3733,6 +3733,68 @@ html.modal-scroll-locked .app-main {
.exercises-page__title { .exercises-page__title {
margin: 0; margin: 0;
} }
.exercises-page__header-actions {
display: flex;
flex-wrap: wrap;
align-items: center;
gap: 10px;
}
.exercises-ai-assistant-toggle {
display: inline-flex;
align-items: center;
gap: 10px;
cursor: pointer;
user-select: none;
font-size: 14px;
color: var(--text2);
padding: 6px 10px;
border-radius: 8px;
border: 1px solid var(--border);
background: var(--surface2);
}
.exercises-ai-assistant-toggle:hover {
border-color: var(--accent-dark, rgba(29, 158, 117, 0.45));
}
.exercises-ai-assistant-toggle:has(input:checked) {
border-color: var(--accent);
background: var(--accent-light, rgba(29, 158, 117, 0.12));
color: var(--accent-dark);
font-weight: 600;
}
.exercises-ai-assistant-toggle input {
position: absolute;
opacity: 0;
width: 0;
height: 0;
pointer-events: none;
}
.exercises-ai-assistant-toggle__track {
position: relative;
flex-shrink: 0;
width: 40px;
height: 22px;
border-radius: 999px;
background: var(--border);
transition: background 0.15s ease;
}
.exercises-ai-assistant-toggle__track::after {
content: '';
position: absolute;
top: 2px;
left: 2px;
width: 18px;
height: 18px;
border-radius: 50%;
background: #fff;
box-shadow: 0 1px 2px rgba(0, 0, 0, 0.2);
transition: transform 0.15s ease;
}
.exercises-ai-assistant-toggle:has(input:checked) .exercises-ai-assistant-toggle__track {
background: var(--accent);
}
.exercises-ai-assistant-toggle:has(input:checked) .exercises-ai-assistant-toggle__track::after {
transform: translateX(18px);
}
.exercises-page-toolbar-tabs { .exercises-page-toolbar-tabs {
margin-bottom: 14px; margin-bottom: 14px;
} }

View File

@ -14,8 +14,6 @@ export default function ExerciseListSearchBar({
exerciseCount, exerciseCount,
allOnPageSelected, allOnPageSelected,
onToggleSelectAllPage, onToggleSelectAllPage,
aiQuickCreateEnabled = false,
onToggleAiQuickCreate,
}) { }) {
return ( return (
<div className="card exercise-search-bar"> <div className="card exercise-search-bar">
@ -50,19 +48,6 @@ export default function ExerciseListSearchBar({
/> />
<div className="exercise-search-bar__actions exercise-search-bar__actions--split"> <div className="exercise-search-bar__actions exercise-search-bar__actions--split">
<div className="exercise-search-bar__actions-main"> <div className="exercise-search-bar__actions-main">
{typeof onToggleAiQuickCreate === 'function' ? (
<button
type="button"
className={
'btn btn-secondary exercise-mine-toggle' +
(aiQuickCreateEnabled ? ' exercise-mine-toggle--active' : '')
}
onClick={onToggleAiQuickCreate}
title="Neue Übung per KI aus dem Suchtext vorschlagen und anlegen"
>
KI-Anlage
</button>
) : null}
<button <button
type="button" type="button"
className={'btn btn-secondary exercise-mine-toggle' + (mineOnly ? ' exercise-mine-toggle--active' : '')} className={'btn btn-secondary exercise-mine-toggle' + (mineOnly ? ' exercise-mine-toggle--active' : '')}
@ -108,13 +93,6 @@ export default function ExerciseListSearchBar({
<p className="exercise-search-hint"> <p className="exercise-search-hint">
Trefferliste aktualisiert sich kurz nach Eingabe. Titel der aktuellen Liste erscheinen als Vorschläge (Pfeil im Trefferliste aktualisiert sich kurz nach Eingabe. Titel der aktuellen Liste erscheinen als Vorschläge (Pfeil im
Feld). Fachliche Filter über Filter zwischen Feldern UND, Auswahl mehrerer Werte je Feld mit ODER. Feld). Fachliche Filter über Filter zwischen Feldern UND, Auswahl mehrerer Werte je Feld mit ODER.
{aiQuickCreateEnabled ? (
<>
{' '}
<strong>KI-Anlage aktiv:</strong> Suchtext als Ausgang für einen KI-Entwurf ohne Treffer oder direkt über
Mit KI anlegen.
</>
) : null}
{exerciseCount > 0 ? ( {exerciseCount > 0 ? (
<> <>
{' '} {' '}

View File

@ -594,13 +594,27 @@ function ExercisesListPageRoot() {
<div className="exercises-page__header"> <div className="exercises-page__header">
<h1 className="page-title exercises-page__title">Übungen</h1> <h1 className="page-title exercises-page__title">Übungen</h1>
{pageTab === 'list' ? ( {pageTab === 'list' ? (
<NavStateLink <div className="exercises-page__header-actions">
to="/exercises/new" <label
returnContext={exercisesModuleReturnContext} className="exercises-ai-assistant-toggle"
className="btn btn-primary" title="Neue Übung per KI vorschlagen — Titel, optional Kurzbeschreibung, Fokusbereich"
> >
+ Neu <input
</NavStateLink> type="checkbox"
checked={aiQuickCreateEnabled}
onChange={(e) => setAiQuickCreateEnabled(e.target.checked)}
/>
<span className="exercises-ai-assistant-toggle__track" aria-hidden="true" />
<span>Neu mit KI-Assistent</span>
</label>
<NavStateLink
to="/exercises/new"
returnContext={exercisesModuleReturnContext}
className="btn btn-primary"
>
+ Neu
</NavStateLink>
</div>
) : ( ) : (
<span aria-hidden="true" /> <span aria-hidden="true" />
)} )}
@ -643,8 +657,6 @@ function ExercisesListPageRoot() {
exerciseCount={exercises.length} exerciseCount={exercises.length}
allOnPageSelected={allOnPageSelected} allOnPageSelected={allOnPageSelected}
onToggleSelectAllPage={toggleSelectAllPage} onToggleSelectAllPage={toggleSelectAllPage}
aiQuickCreateEnabled={aiQuickCreateEnabled}
onToggleAiQuickCreate={() => setAiQuickCreateEnabled((v) => !v)}
/> />
{showQuickCreateOffer ? ( {showQuickCreateOffer ? (
@ -663,7 +675,7 @@ function ExercisesListPageRoot() {
onRunAi={runQuickCreateAiSuggest} onRunAi={runQuickCreateAiSuggest}
hint={ hint={
aiQuickCreateEnabled aiQuickCreateEnabled
? 'KI-Anlage: Titel aus Suche oder manuell; Kurzbeschreibung optional — leer für freien KI-Vorschlag, ausgefüllt als Ausgangsidee.' ? 'Titel aus Suche oder manuell; Kurzbeschreibung optional — leer für freien KI-Vorschlag, ausgefüllt als deine Ausgangsidee.'
: undefined : undefined
} }
/> />