Skip to content

Visual redesign: premium Scandinavian energy dashboard#303

Merged
tvup merged 18 commits intodevelopfrom
feature/visual-redesign
Mar 28, 2026
Merged

Visual redesign: premium Scandinavian energy dashboard#303
tvup merged 18 commits intodevelopfrom
feature/visual-redesign

Conversation

@tvup
Copy link
Copy Markdown
Owner

@tvup tvup commented Mar 28, 2026

Summary

  • Complete visual overhaul with deep teal/amber Scandinavian design palette
  • Sticky navbar with gradient accent bar, Font Awesome icons, and active state detection
  • Hero landing page with feature cards replacing the basic welcome card
  • All feature pages upgraded with icon card headers and collapsible data panels (replaces raw JSON <pre> tags)
  • Elegant 3-column footer, animations, flatpickr theming, mobile responsive improvements

Files changed

  • _variables.scss — Full Bootstrap 5 variable override system
  • app.scss — All new design tokens, components, animations
  • layouts/app.blade.php — Navbar + footer restructure
  • home.blade.php — Hero section redesign
  • 7 feature pages — Card headers + data panels

Test plan

  • npm run build — builds without errors
  • artisan test --compact — 75 tests passed
  • phpstan — 0 errors
  • Visual review of all pages in browser

🤖 Generated with Claude Code

tvup and others added 18 commits March 28, 2026 17:02
Complete visual overhaul of the PowerUse frontend:

- New color system: deep teal (#0F766E) primary, amber accent
- Bootstrap 5 variable overrides for cards, inputs, buttons, borders
- Sticky navbar with gradient accent bar, icons, and active states
- Hero landing page with feature cards and video tutorial
- Card headers with gradient icons and subtitles on all pages
- Raw JSON output wrapped in collapsible data panels
- Elegant footer with 3-column layout
- Animations: fadeInUp, slideInDown for alerts, hover effects
- Flatpickr theme override to match new palette
- Modernized PWA nudge modal
- Responsive improvements for mobile
- Additional Nunito font weights (300, 600, 800)

Co-Authored-By: Claude Opus 4.6 (1M context) <[email protected]>
- Comprehensive .btn base styles: consistent font, padding, border-radius,
  transitions, flex layout with gap for icons
- All button variants styled: primary, secondary, danger, info, outline,
  link, sm, lg
- Tailwind button component overrides to match Bootstrap design system
- Added icons to ALL submit/save buttons across the app (paper-plane,
  floppy-disk, trash, right-to-bracket, user-plus)
- Consistent spacing: mt-3 wrapper divs instead of random mt-2 on buttons
- Form submit buttons have min-width for visual consistency
- Disabled state styling with reduced opacity

Co-Authored-By: Claude Opus 4.6 (1M context) <[email protected]>
Ensures vulnerable data (spotprices, metering points, charges) can be
safely backed up before a full data reload, preventing historical data loss.

Co-Authored-By: Claude Opus 4.6 (1M context) <[email protected]>
- Remove inline-flex/gap from .btn base (caused off-center text)
- Use margin-right on icons instead for proper text alignment
- Add .btn-action class (min-width: 12rem) for uniform button widths
- Restructure MeteringPoint.vue and Charge.vue headers with
  form-section layout, proper form controls, and consistent icons
- Add icons to all Vue component buttons (plus, download, floppy-disk,
  pen, trash, xmark)
- Uniform button spacing with d-flex gap-2 wrappers

Co-Authored-By: Claude Opus 4.6 (1M context) <[email protected]>
Change .btn-action to display:block with width:100% and max-width:18rem
so all action buttons in a section have the same width regardless of
text length.

Co-Authored-By: Claude Opus 4.6 (1M context) <[email protected]>
Use inline-flex with justify-content:center and fixed width:18rem
so icon + text are always centered within the uniform-width button.

Co-Authored-By: Claude Opus 4.6 (1M context) <[email protected]>
FA7 SCSS only defines .fas/.far classes, not .fa-solid/.fa-regular.
All our templates use fa-solid which was invisible. Extend the aliases
so icons render correctly.

Co-Authored-By: Claude Opus 4.6 (1M context) <[email protected]>
Icons were not rendering due to FA7 SCSS class mismatch. Simplify
by removing icons from Vue component action buttons and using
display:block + text-align:center for reliable text centering.

Co-Authored-By: Claude Opus 4.6 (1M context) <[email protected]>
Add error handling for nonexistent tables, fix PHPStan type issues
with PendingCommand and file_get_contents return types.

Co-Authored-By: Claude Opus 4.6 (1M context) <[email protected]>
Remove col-sm-6/col-sm-10 wrappers, panel/row nesting, and col-lg-2
spacer. Input fields now sit in card-body with same padding as the
action buttons above, so everything aligns to the left edge.

Co-Authored-By: Claude Opus 4.6 (1M context) <[email protected]>
Co-Authored-By: Claude Opus 4.6 (1M context) <[email protected]>
@tvup tvup merged commit ffcc949 into develop Mar 28, 2026
2 checks passed
@tvup tvup deleted the feature/visual-redesign branch March 28, 2026 18:32
tvup added a commit that referenced this pull request Mar 28, 2026
* Support 15-minute electricity market resolution and improve Smart-Me integration

- Add Quarter resolution support to ElOverblik API with fallback chain (Quarter → Actual → Hour)
- Handle mixed resolution: average 4 quarter spot prices for hourly consumption (Danish industry standard)
- Update ProcessController/ElController for dynamic spot price resolution detection
- Auto-fill Smart-Me credentials from user profile in forms
- Move Smart-Me credentials from .env/config to user profile (database)
- Extract seeder credentials to untracked user_credentials.json
- Dynamic grid operator list from datahub_price_lists instead of hardcoded
- Consolidate lang directories (merge lang/ into resources/lang/, delete lang/)
- Fix paasword typo in config/services and all references
- Fix WOH! debug statement in vendor ElOverblikApiBase
- Add API access logging to Api\ElController
- Regenerate test fixtures with real 15-min API data (2025-10-01)
- Remember price area selection via cookie on /el page

Co-Authored-By: Claude Opus 4.6 (1M context) <[email protected]>

* Fix token reuse bug in GetMeteringData - create new API instance when refresh token changes

The ElOverblik API instance was cached on the service object and reused
even when a different user's refresh token was passed, causing the wrong
token to be sent to the ElOverblik API.

Co-Authored-By: Claude Opus 4.6 (1M context) <[email protected]>

* A

* Remove env/config fallback for refresh token - tokens must come from database only

CalculateUpcommingInvoice no longer falls back to config('services.energioverblik.refresh_token').
Removed energioverblik config block entirely. Refresh tokens are now exclusively
stored per-user in the database, preventing stale env tokens from being used.

Co-Authored-By: Claude Opus 4.6 (1M context) <[email protected]>

* bump eloverblikapi to v2.1.0 for compatibility

* Fix Smart-Me credentials using numeric instead of associative array keys in API ElController

Co-Authored-By: Claude Opus 4.6 (1M context) <[email protected]>

* Fix missing grid/Energinet tariffs in bill - use caller's dataSource for charges lookup

Co-Authored-By: Claude Opus 4.6 (1M context) <[email protected]>

* Filter DATAHUB tariffs and subscriptions by billing period to exclude expired entries

Co-Authored-By: Claude Opus 4.6 (1M context) <[email protected]>

* Fix charges cache key to include dataSource and skip empty cached results

Co-Authored-By: Claude Opus 4.6 (1M context) <[email protected]>

* Use inline prices from DATAHUB tariffs instead of DatahubPriceList lookup

DATAHUB getCharges API returns tariff names that may not match
DatahubPriceList Note values (e.g. "Nettarif C" vs "Nettarif C time").
Since DATAHUB tariffs already include prices, use them directly.

Co-Authored-By: Claude Opus 4.6 (1M context) <[email protected]>

* Fall back to DATAHUB for charges when POWERUSE returns empty results

Co-Authored-By: Claude Opus 4.6 (1M context) <[email protected]>

* Preserve end_date value after form submission instead of resetting to today

Co-Authored-By: Claude Opus 4.6 (1M context) <[email protected]>

* Handle 96-position (15-min) tariff prices from DATAHUB API

When tariffs have 96 prices (PT15M resolution), index by
hour*4 + quarter instead of just hour.

Co-Authored-By: Claude Opus 4.6 (1M context) <[email protected]>

* Skip date filtering of DATAHUB charges when start/end dates are null

Fixes el-charges page which calls getCharges without date parameters.

Co-Authored-By: Claude Opus 4.6 (1M context) <[email protected]>

* Preserve Smart-me checkbox state after form submission

Use old('_token') to detect form submission, so an unchecked checkbox
stays unchecked instead of reverting to Cookie/user defaults.

Co-Authored-By: Claude Opus 4.6 (1M context) <[email protected]>

* Always try DatahubPriceList lookup before falling back to inline DATAHUB prices

DATAHUB getCharges API returns stale prices from when tariffs were created.
DatahubPriceList has authoritative, current prices. Now tries exact match
first, then GLN + name LIKE fallback (e.g. "Nettarif C" matches
"Nettarif C time"), and only uses inline prices as last resort.

Co-Authored-By: Claude Opus 4.6 (1M context) <[email protected]>

* Fix findDatahubPriceList type hint to accept Eloquent Charge models

Co-Authored-By: Claude Opus 4.6 (1M context) <[email protected]>

* Add temporary debug logging for tariff price resolution

Co-Authored-By: Claude Opus 4.6 (1M context) <[email protected]>

* Add more debug logging for DatahubPriceList price resolution

Co-Authored-By: Claude Opus 4.6 (1M context) <[email protected]>

* temp: log first 8 price lookups per tariff

* temp: increase debug log to 30

* temp: log only hours >= 6

* temp: log hour distribution

* bump eloverblikapi to v2.1.1 and update revision number

* Fix cumulative rounding error by rounding only after all intervals

Moving round() out of the per-interval loop eliminates systematic
rounding bias, especially for small per-kWh prices like Elafgift
(0.008) where each 15-min interval rounded up from 0.007 to 0.01.

Also removes temporary debug logging.

Co-Authored-By: Claude Opus 4.6 (1M context) <[email protected]>

* Persist overhead and subscription values in cookies across sessions

Co-Authored-By: Claude Opus 4.6 (1M context) <[email protected]>

* Add searchable select component for grid operator (#299)

* Add searchable select component for grid operator and minor cleanups

Replace plain HTML select with a searchable dropdown for grid operator
selection in totalprices form. Add English language file and bump revision.

Co-Authored-By: Claude Opus 4.6 (1M context) <[email protected]>

* no dont

* no dont

* Fix XSS vulnerability, add i18n support, and bump revision

- Replace addslashes() with @js() directive to prevent XSS in searchable-select
- Wrap hardcoded Danish strings in __() for i18n (placeholder and no-results)
- Add 'Type to search...' and 'No results' keys to lang/php_en.json
- Add trailing newline to lang/php_en.json

Co-Authored-By: Claude Opus 4.6 (1M context) <[email protected]>

* Fix review findings: Enter key, DOMContentLoaded, i18n, uid collision

- Fix Enter key blocking form submit when dropdown is closed
- Replace setTimeout(500) with DOMContentLoaded for reliable init
- Use Str::random() in uid to prevent collisions with same-name instances
- Add Danish translations for searchable-select strings to da.json
- Remove redundant lang/php_en.json (resources/lang/en/ already covers it)
- Ignore root /lang/ directory in .gitignore

Co-Authored-By: Claude Opus 4.6 (1M context) <[email protected]>

* Improve accessibility, explicit Str import, and label toString guard

- Add ARIA combobox pattern: role=combobox, aria-expanded, aria-controls, role=listbox
- Use explicit \Illuminate\Support\Str::random() instead of facade shorthand
- Guard option.label with String() to handle non-string values
- Centralize show/hide list into showList()/hideList() for consistent aria-expanded state

Co-Authored-By: Claude Opus 4.6 (1M context) <[email protected]>

---------

Co-authored-by: Claude Opus 4.6 (1M context) <[email protected]>

* Add loading spinner to submit button on el form

Shows a Bootstrap spinner, disables the button, and changes text to
"Processing..." on form submit to prevent double-clicks and give
visual feedback.

Co-Authored-By: Claude Opus 4.6 (1M context) <[email protected]>

* Update ci.yml

* Update ci.yml

* Update ci.yml

* Add RefreshDatabase trait to tests missing database migrations

Tests were failing in CI with "no such table: users" because ParaTest
creates isolated in-memory SQLite databases per worker process, and
without RefreshDatabase the migrations never run.

Co-Authored-By: Claude Opus 4.6 (1M context) <[email protected]>

* update tariff and cost values to reflect new rates

* Fix MeteringPointControllerTest by generating Passport keys in setUp

The test directly instantiates MeteringPointController whose constructor
calls auth('api')->check(), triggering Passport key loading. Generate
keys on first run so the guard can resolve without errors.

Co-Authored-By: Claude Opus 4.6 (1M context) <[email protected]>

* Fix all PHPStan errors for clean CI

- Add explicit nullable types (?Type) for PHP 8.4 compatibility (12 files)
- Fix Model relationship PHPDoc generics with static type
- Fix round() and json_decode type safety issues
- Fix unreachable else branch in GetSpotPrices
- Fix PHPDoc @var types in GetSmartMeMeterDataTest
- Fix GetDatahubPriceLists return type annotation
- Add PHPStan ignore for Eloquent HasMany covariance (known Larastan issue)

Co-Authored-By: Claude Opus 4.6 (1M context) <[email protected]>

* fix password change command and clean imports in tests

* fix HTML tag typo in energy data display section

* Update composer.lock for PHP 8.5 compatibility

Updates paratest, lcobucci/jwt, passport and dependencies to versions
that support PHP 8.5.

Co-Authored-By: Claude Opus 4.6 (1M context) <[email protected]>

* chore(deps): update all patch dependencies (#294)

Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>

* Pin paratest to ~7.8.5 to avoid phpunit 12 conflict on PHP 8.5

The ^7.5.7 constraint resolved to v7.19.2 on CI which requires
phpunit/php-code-coverage ^12, conflicting with phpunit 11. The 7.8.x
line supports both phpunit 11 and PHP 8.5.

Co-Authored-By: Claude Opus 4.6 (1M context) <[email protected]>

* bump dev dependencies for testing and quality tools

* Upgrade to PHPUnit 13, PHPStan 2, and Larastan 3

- phpunit/phpunit: ^11.4 → ^13.0
- brianium/paratest: ~7.8.5 → ^7.19.2
- larastan/larastan: ^2.9 → ^3.0
- phpstan/phpstan-phpunit: ^1.4 → ^2.0
- phpstan/phpstan-mockery: ^1.1 → ^2.0
- Migrate @Depends annotation to PHP 8 attribute
- Fix all new PHPStan v2 / Larastan v3 strict errors
- Update phpunit.xml schema to 12.0

Co-Authored-By: Claude Opus 4.6 (1M context) <[email protected]>

* chore(deps): update all minor dependencies (#287)

Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>

* Remove redundant array_values() call in GetSpotPricesTest

PHPStan 2 correctly identifies that the array is already a list,
making array_values() a no-op.

Co-Authored-By: Claude Opus 4.6 (1M context) <[email protected]>

* Fix GetSpotPricesTest for DayAheadPrices API migration

- Add helpers.php to composer autoload files (lost during merge)
- Move parent::setUp() before fixture loading
- Update test to use DayAheadPrices endpoint and TimeDK/DayAheadPriceDKK
  column names matching the current GetSpotPrices implementation

Co-Authored-By: Claude Opus 4.6 (1M context) <[email protected]>

* update dependencies to latest versions for security and features

* Add charge_tariff_mappings table for deterministic tariff matching

Introduces a persistent mapping between Charge names (from ElOverblik)
and DatahubPriceList entries (from EnergiDataService), replacing
fragile fuzzy LIKE matching with direct lookups.

- New migration: charge_tariff_mappings with unique(charge_name, gln)
- New model: ChargeTariffMapping
- Modified findDatahubPriceList() to check mapping table first,
  auto-create mappings on successful Stage 1/2 match, and log
  warnings when no match is found
- 3 feature tests covering auto-creation and reuse of mappings
- Fix ChargesManualLoad command description

Co-Authored-By: Claude Opus 4.6 (1M context) <[email protected]>

* Add Laravel Forge deployment status badge to README

* fix filtering logic for note prefix matching in tests

* Fix fontsource import for Vite 7 compatibility

Replace scss/mixins.scss import with direct CSS imports for Nunito
font weights 400 and 700. The scss mixin approach broke with the
Vite 7 Sass resolver.

Co-Authored-By: Claude Opus 4.6 (1M context) <[email protected]>

* Visual redesign: premium Scandinavian energy dashboard (#303)

* Visual redesign: premium Scandinavian energy dashboard

Complete visual overhaul of the PowerUse frontend:

- New color system: deep teal (#0F766E) primary, amber accent
- Bootstrap 5 variable overrides for cards, inputs, buttons, borders
- Sticky navbar with gradient accent bar, icons, and active states
- Hero landing page with feature cards and video tutorial
- Card headers with gradient icons and subtitles on all pages
- Raw JSON output wrapped in collapsible data panels
- Elegant footer with 3-column layout
- Animations: fadeInUp, slideInDown for alerts, hover effects
- Flatpickr theme override to match new palette
- Modernized PWA nudge modal
- Responsive improvements for mobile
- Additional Nunito font weights (300, 600, 800)

Co-Authored-By: Claude Opus 4.6 (1M context) <[email protected]>

* Polish button system for consistent sizing and styling

- Comprehensive .btn base styles: consistent font, padding, border-radius,
  transitions, flex layout with gap for icons
- All button variants styled: primary, secondary, danger, info, outline,
  link, sm, lg
- Tailwind button component overrides to match Bootstrap design system
- Added icons to ALL submit/save buttons across the app (paper-plane,
  floppy-disk, trash, right-to-bracket, user-plus)
- Consistent spacing: mt-3 wrapper divs instead of random mt-2 on buttons
- Form submit buttons have min-width for visual consistency
- Disabled state styling with reduced opacity

Co-Authored-By: Claude Opus 4.6 (1M context) <[email protected]>

* Add db:export command for backing up database tables to CSV fixtures

Ensures vulnerable data (spotprices, metering points, charges) can be
safely backed up before a full data reload, preventing historical data loss.

Co-Authored-By: Claude Opus 4.6 (1M context) <[email protected]>

* Fix button layout and Vue component styling

- Remove inline-flex/gap from .btn base (caused off-center text)
- Use margin-right on icons instead for proper text alignment
- Add .btn-action class (min-width: 12rem) for uniform button widths
- Restructure MeteringPoint.vue and Charge.vue headers with
  form-section layout, proper form controls, and consistent icons
- Add icons to all Vue component buttons (plus, download, floppy-disk,
  pen, trash, xmark)
- Uniform button spacing with d-flex gap-2 wrappers

Co-Authored-By: Claude Opus 4.6 (1M context) <[email protected]>

* Fix action buttons to have uniform width

Change .btn-action to display:block with width:100% and max-width:18rem
so all action buttons in a section have the same width regardless of
text length.

Co-Authored-By: Claude Opus 4.6 (1M context) <[email protected]>

* Center button text and icons in action buttons

Use inline-flex with justify-content:center and fixed width:18rem
so icon + text are always centered within the uniform-width button.

Co-Authored-By: Claude Opus 4.6 (1M context) <[email protected]>

* Add fa-solid/fa-regular aliases for Font Awesome 7 SCSS

FA7 SCSS only defines .fas/.far classes, not .fa-solid/.fa-regular.
All our templates use fa-solid which was invisible. Extend the aliases
so icons render correctly.

Co-Authored-By: Claude Opus 4.6 (1M context) <[email protected]>

* Remove icons from action buttons, use display:block for centering

Icons were not rendering due to FA7 SCSS class mismatch. Simplify
by removing icons from Vue component action buttons and using
display:block + text-align:center for reliable text centering.

Co-Authored-By: Claude Opus 4.6 (1M context) <[email protected]>

* Fix PHPStan errors in db:export command and test

Add error handling for nonexistent tables, fix PHPStan type issues
with PendingCommand and file_get_contents return types.

Co-Authored-By: Claude Opus 4.6 (1M context) <[email protected]>

* Align metering point form fields flush with buttons

Remove col-sm-6/col-sm-10 wrappers, panel/row nesting, and col-lg-2
spacer. Input fields now sit in card-body with same padding as the
action buttons above, so everything aligns to the left edge.

Co-Authored-By: Claude Opus 4.6 (1M context) <[email protected]>

* Add icons to form submit buttons across all blade templates

Co-Authored-By: Claude Opus 4.6 (1M context) <[email protected]>

* Update fixture exports from db:export

Co-Authored-By: Claude Opus 4.6 (1M context) <[email protected]>

* fix error handling in DbExport command and clean imports

* allow manual trigger and remove push event from CI

* Add card-body class to single metering point container

* align navbar links for consistent vertical centering

* remove icons from home page hero and features for cleaner look

* Increase progress bar max to match data size

---------

Co-authored-by: Claude Opus 4.6 (1M context) <[email protected]>

---------

Co-authored-by: Claude Opus 4.6 (1M context) <[email protected]>
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant