Feature/dino UI restyle - #20
Open
tulas75 wants to merge 17 commits into
Open
Conversation
Retire the top toolbar on wide viewports and give the sidebar three stacked zones: brand and collapse toggle, grouped navigation (User / Administration), and a utility footer with the sync control, the utility icons and the active user card. Below 960px a slim bar (drawer toggle, logo, sync) replaces it and the sidebar becomes an overlay drawer. The toolbar previously carried twelve unrelated affordances while the sidebar held only route links, and it spent ~65px of viewport on a bar with no page context. The route links keep their existing config, permission gating and tour anchors; most of the redesign is a re-layout rather than new behaviour. Shell: - Expose the layout as a `--dino-shell-*` custom property API, following the `--dino-survey-*` pattern already used by the public survey, and rewrite the pico deployment theme to override those tokens instead of Material internals. - Drive all responsive rules off a single `dino-shell-compact` host class. The stylesheet used to declare 767/768/992px media queries alongside CDK breakpoint checks in the template, which disagreed between ~600 and 960px. - Add a width-only `wide` breakpoint: CDK `Breakpoints.Web` requires 1280px in landscape, which would push an ordinary desktop window into the compact layout now that the sidebar is the only navigation. - Size the sidebar and the page offset from the same host class rather than through `MatSidenavContainer.autosize`, which recomputed the content margin from a MutationObserver and read clientWidth mid-transition, leaving the content overlapped until an unrelated DOM change forced a re-measure. - Add the group headings, the avatar initials, the active role label, the visible app version and the time elapsed since the last replication. Page header: - Rewrite `dino-breadcrumbs` in place as an overline plus title, so every call site picks it up unchanged, and add an `actions` slot for page level actions. Top level pages fall back to their section group, shared by the new `ShellContextService`. Shared pieces: - Extract the light/dark control into `@dino/material/theme-switch`, replacing the slide toggle in the shell and the copy of it in the login page. - Extract `LangService` so the shell language menu and `dino-lang-selector` share one persistence path. - Record `DataService.lastSyncAt` on every completed replication cycle. - Drop the nav item styles that `_sidenav-theme.scss` duplicated from `main-nav.scss`, and the unused `setShowNavLabels` input. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
On compact viewports the slim top bar already carries the logo and the drawer toggle, so the sidebar's own brand row repeated both a few pixels below, giving the open drawer two logos and two menu buttons. Render the brand row only in the wide layout. The nav list becomes the first child of the sidebar's flex column, which already has its own padding, so no stylesheet change is needed. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
The nav element carries flex: 1 1 auto, so it is what holds the sync control, the utility icons and the user card down at the bottom of the sidebar. It was dropped from the DOM while the sections loaded, which let that whole block ride up under the logo for the length of the first replication, then snap back down. Move the *ngIf onto the list inside it so the flexible zone stays mounted and only its contents wait on the data. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
…is up The initialization screen leaves nothing to navigate to, so an expanded sidebar spends the first replication showing links that cannot be followed. Collapse it to the rail for the duration and restore whatever state it had once the data lands. The state is captured rather than assumed, so a deployment that configures initialExtendedSidenav: false stays collapsed afterwards, and toggling the sidebar by hand during the sync drops the pending restore. Only on wide viewports: the compact drawer is already closed during the sync, and opening it unasked would cover the page the user was waiting for. The subscription takes just the first true/false pair, so the routed pages that push their own loading state into the same subject never fold the sidebar away. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
The dark logo set kept the orange and blue accent arcs from the colour version, and the sidebar never reached it anyway: the default darkLogoPath pointed at dino-bar-logo-light.svg, so dark theme rendered the navy wordmark on a #1b1f24 sidebar. Recolour the two accent arcs to white in the three dark variants, matching the monochrome-on-dark lockups on page 4 of the brand guide, and point the sidebar default at dino-bar-logo-dark.svg, which was already in the repo but unused. The geometry is untouched, so a deployment overriding logoDark is unaffected. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
The header carried the stacked lockup, which spends its height on a wordmark too small to read at the 32px the brand row allows. Switch it to the horizontal one from page 1 of the brand guide, in the sidebar brand row and in the compact top bar. The collapsed rail is 68px wide, so the lockup would shrink to an illegible strip there: add a 'logoMarkPath' input and drop to the mark on its own while the sidebar is collapsed. It falls back to logoImagePath when not given, so a deployment with a single logo behaves as before, and dinoapp resolves it from the same customImagesConfig keys - substituting the DINO mark under a configured third party logo would be putting our brand on their shell. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
dino-login-light.svg was an Illustrator export that painted its six shapes through five opacity masks, each one a 442x130 embedded PNG. The geometry scaled cleanly but the masks did not: anywhere the logo is drawn smaller than its native size the browser downsamples them, which is why the header logo looked soft at 32px and sharp when opened on its own. Redraw it from page 1 of the brand guide as six flat paths, no masks and no rasters, in a group scaled into the 442x130 box the file already declared. Drop in identical: overlaying the two at 200px shows no offset, and the file goes from 8.6K to 2.6K. The other five logo assets were already mask-free. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Toggling the theme applied it and emitted the change, but never wrote it down. On the next start the service restored dino_theme_default, whose isDarkTheme is only refreshed when a theme preset is saved, so the toggle was undone by whatever the last save - or the environment config - had frozen in. Store the choice under its own dino_dark_mode key on every setDarkMode call, so every entry point persists it: the sidebar switch, the User Area dialog and the login page alike. On start it is read before the first write and applied after the preset is loaded, so it outranks the preset's own stale flag while a preset loaded by hand from the User Area still applies the dark mode it was saved with. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Opening a report or the dashboard spun the colour mark whatever the theme, because both components bound a single lightSpinnerPath - and its default was spinnerdino.png, a colour raster with no dark counterpart. On the dark page background the navy ring all but vanishes. The shell had resolved this correctly for its own spinner and its logos, so the same twenty lines existed in three copies and two of them were wrong. Collect them in themed-images.ts: one place naming the light/dark pair behind each role (header lockup, rail mark, loading spinner) and one helper turning a pair into the path for the active theme. All three components now read from it, and the report loaders get the vector mark the shell already used. Deployment overrides keep their existing meaning: a configured light image with no dark variant is used in both themes rather than being replaced by ours. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Area utente was a 95vw dialog holding six accordion panels. The accordions were there only to keep five unrelated settings groups from overflowing a format meant for a single decision, backup and restore had no room for its confirmation and result states, and the area had no URL: it could not be linked, refreshed or reached with Back. It is now a routed page at /user-area/:tab inside the shell, with the panels as tabs and API Keys and Credits merged into one AI tab. The sidebar robot goes to /user-area/ai, the user menu item to the page. No component was added beyond the thin dinoapp page wrapper every route already has; the layout follows the mockup but the chrome is the app's own, dino-breadcrumbs and mat-tab-group over the --dino-shell-* tokens, so the page re-skins with a deployment theme. Tabs are built as data and the index is derived from the same array that renders them, so a hidden tab cannot leave the group pointing at the wrong panel. A slug naming a tab the user does not have reports itself back for the host to correct. trackBy keeps the bodies alive across a rebuild, so switching tabs does not discard what was typed in the others. Behaviour changes worth naming: - Theme colors no longer repaint the app as they are picked. They drive a preview and reach the app on Salva tema, which means a preset name is now required to apply a color, as the design specifies. - The API key is read only: masked, with show and copy. It is provisioned at login, so an account without one gets a line saying so rather than a field it cannot fill. - The dark mode toggle moves from the dialog header to the Theme tab. The collapsed rail offers no theme control, so dropping it outright would have taken one away. Also fixed, all exposed by the conversion: - The section highlight matched section.url as a substring of the whole URL, so /user-area/ai lit up the AI item. It now matches the first path segment. - A failed restore left the spinner running forever; only the dialog closing had ever stopped it. - Cancelling a restore left the file input holding the file, so picking the same file again fired no change event. - The theme preset autocomplete destructured the control value as an array and filtered on its first character. - changePassword never set processing, so the submit button stayed live during the request. The shell no longer imports UserAreaModule, so the page and its color picker, clipboard and autocomplete dependencies leave the eager bundle for a lazy 35 kB chunk. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
The version line at the foot of the user menu is a plain div, not a .mat-mdc-menu-item, so it inherited no menu foreground and fell back to near black - unreadable on the dark menu panel, and dimmed further by an opacity of 0.6. It now takes the same colour token the menu items use, which the theme redefines under .isDarkTheme, and dims by colour rather than by an opacity that would eat the contrast a second time. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Three defects in the restyled theme and backup tabs: The colour picker was unusable. The directive sat on the matPrefix swatch, so ngx-color-picker inserted its popup inside the form field, where the field clipped it down to a strip of gradient. The directive goes back on the mat-form-field - where it worked before the restyle - and each field gains a positioned wrapper, so the popup is placed against the field it belongs to instead of against the scrolling tab body. That tab body no longer clips either: Material scrolls it, which would cut off a popup hanging below the last field, and nothing here needs its own scrollport because the shell scrolls the page. The readonly hex took Material's dimmed readonly grey, which is not a colour to read a hex in. It now takes the field's own foreground in the mono face the rest of the page uses. Restore rendered as bare text: mat-stroked-button was written on a span, and the directive only matches button and a. It is a real button now, opening the file input it sits beside. Also hoists the three validation labels out of the template. The formatter wraps a long interpolation, and a wrap inside a string literal puts a newline into the message itself. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
The routed user area landed with its strings in English and Italian only, so the other dictionaries fell through to the English source text. Audits the 46 keys the page uses against all eight dictionaries and adds the 182 that were missing: 27 each to esp, fra and prt, 26 to ar and ukr, 41 to uga and 4 to eng and ita. uga is an English placeholder dictionary - every entry maps to its English string - so its additions follow that convention. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
The panel was a bare list of menu items: one line each, truncated to a single row and readable only by hovering for the tooltip, with no sense of when anything arrived and a mini-fab per row for the ones that led somewhere. It gets the structure the design asks for: a header carrying the unread count and the mark-all action, a scrolling list under sticky day headings, and a footer link. A row is now a dot, an icon, the text - wrapped, not truncated - the age, and an arrow only when it goes somewhere. Two things are derived rather than stored. Notifications are grouped by calendar day into Today, Yesterday and Earlier, headings following the data so a day with nothing in it produces none. Within a day, a run of repeats of the same text collapses into one row with a count, so a job that notifies on every retry costs one row instead of ten; marking that row read walks the whole run. Both live in notification-groups.ts as pure functions, with the instant they measure against injected so they can be asserted. The rows are plain buttons rather than mat-menu-items: marking one read is not a choice that ends the panel, so it must not close it. The two entries that do leave - a row with a url, and the footer - close it through the trigger themselves. The panel is drawn in the CDK overlay, outside dino-main-nav, so the --dino-shell-* tokens do not reach it. It carries its own neutrals on the same scale, with the dark theme redefining only the values. Also fixes mark-all-as-read, which patched every notification in the collection without checking whether the user was already a reader, so each click appended their id to `readers` a second time. The mockup's sender name, initials avatar and title/body split are not in this commit: the Notification model carries none of them, and the row shows the notification's own type icon in their place. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
The restyled panel names its day groups, its ages and its unread count, none of which existed as keys. Adds the nine new ones to all seven translated dictionaries, plus the two the panel already used that uga was missing. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
No description provided.