Boban Blaskovic
|
7c6ea8d9f0
|
feat(tasks): separate Runner modal — Start actually runs the task
Before: Both info-icon (Details) and Start button opened the same
modal (tasks.modals.detail). Made no sense — Start should DO the task,
not just show metadata.
Now:
- Info-icon (i) -> tasks.modals.detail (read-only metadata)
- Start / Wiederholen-> tasks.modals.runner (interactive quiz)
New: App\Livewire\Tasks\Modals\Runner
Multi-step quiz modal with:
- 4-step progress bar (Frage X / Y + colored bar)
- Question + 4 answer options (2x2 grid, Tailwind cards)
- submitAnswer(int $option) advances step + tallies correctAnswers
- finished state shows trophy (passed) or arrow-path (partial)
- restart() resets quiz to step 1
- closeModalOnClickAway() = false (forces explicit cancel/finish)
- 2xl max-width for comfortable reading
Tasks/Index::startTask() now dispatches tasks.modals.runner via
$this->js("Livewire.dispatch('openModal', ...)") — same dispatch pattern
as before, different target component.
Placeholder data: 4 multiplication questions hardcoded. Future iteration
should load task content from DB (TaskItem / Question models).
Tests:
- TasksRunnerModalTest (10 tests, 25 assertions):
* Runner extends ModalComponent + alias resolves
* Step 1 renders question + 4 options
* Correct answer increments correctAnswers + advances step
* Wrong answer advances step without point
* Final step sets finished=true
* restart() resets state
* closeModalOnClickAway = false
* Progress label "Frage X / Y"
* Success path shows trophy
- TasksStartButtonTest updated:
* Asserts startTask emits dispatch with 'tasks.modals.runner'
(NOT 'tasks.modals.detail')
* Asserts info-button still routes to detail
- 167 tests passed, 0 failed, 0 skipped
Verification:
- All 8 modal aliases resolve via livewire.finder
- All 8 page routes return 302 unauth
- npm build OK
- No HTTP / no console errors expected
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
|
2026-05-22 21:59:51 +02:00 |
Boban Blaskovic
|
7e6d0d4ab4
|
feat(ui): dashboard MVP — feature-folders, lazy skeletons, wire-elements modals, brand logos
Major refactor + UX polish for authenticated dashboard MVP.
Architecture:
- Feature-based folder structure: app/Livewire/<Feature>/{Index, Modals/*}
Dashboard, Subjects, Tasks, PhotoHelp, Rewards, Progress, Notifications, Settings
- Matching view structure: resources/views/livewire/<feature>/{index, modals/*}.blade.php
- Removed legacy Pages/ and Modals/ top-level folders
Modals (wire-elements/modal v3):
- 7 modal components extending LivewireUI\Modal\ModalComponent
- Vendor view override: z-50 (above sidebar z-20), items-center justify-center,
bg-bg-soft surface, role=dialog + aria-modal, design-token-driven backdrop
- Server-side dispatch uses ->to('livewire-ui-modal') for cross-component routing
URL state + skeleton:
- Tasks + Notifications + Settings use #[Url(as, keep:true)] with allowlist
validation in mount()/setSection()/setFilter() to block injection
- Tasks startTask + repeatTask actions dispatch openModal targeted at modal
- All 8 main pages declare #[Lazy] + placeholder() returning a page-level
skeleton (animate-pulse, bg-bg-soft container, bg-line bars) so first paint
is structured instead of blank
Skeleton/no-jump:
- Skeleton container uses bg-bg-soft (matches table card surface) — no color
jump between skeleton and resolved table
- Settings sub-nav renders active state server-side (no Alpine :class flicker)
with @if-server-render instead of x-show
- Font flicker eliminated: font-display: block + <link rel="preload"> on both
layouts for Plus Jakarta Sans + JetBrains Mono
Logos / PWA:
- public/logo/, public/icons/, public/manifest.webmanifest deployed per
Logos/DEPLOY.md
- Brand component (default / wordmark / icon-only variants) with href prop
- Favicon SVG/ICO + apple-touch-icon + manifest tags in dashboard + guest layouts
- Sidebar brand wires to route('dashboard')
Layout / a11y:
- Sidebar fixed left (top-0, h-screen, w-60) with header+footer shrink-0 and
scrollable content
- Topbar sticky with z-10
- Sidebar uses x-layout.brand :href="route('dashboard')"
- Logout: POST /logout route + sidebar-user widget with @csrf form button
Bug fixes:
- Tasks rows are passive divs (not buttons) with explicit info-icon + Start
button — eliminates nested-button invalid HTML
- Tasks Start/Wiederholen buttons wire:click to startTask/repeatTask actions
(previously did nothing)
- Modals centered + above sidebar z-index
- Settings section sub-nav no longer flickers on hydration
- public/hot cleanup: Vite runs as docker compose service with auto-restart
Test infrastructure:
- Pest beforeEach calls Livewire::withoutLazyLoading() so #[Lazy] components
hydrate fully under test
- 157 tests passing, 0 skipped, 0 failed (411 assertions)
- New test files:
AssetReachabilityTest, BrandAssetsTest, FontLoadingTest, LazySkeletonTest,
LogoutTest, ModalLayoutTest, ModalsTest, NoNestedButtonsTest,
SettingsNavTest, SidebarPagesTest, TasksStartButtonTest, UrlStateTest
Config:
- config/sidebar.php as single source of truth for sidebar nav items
- config/reverb.php allowed_origins set
- Test DB isolated: phpunit.xml DB_DATABASE=lernschiff_test +
tests/TestCase.php refreshApplication override
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
|
2026-05-22 21:36:04 +02:00 |