Skip to content

Conversation

@4gray
Copy link
Owner

@4gray 4gray commented Dec 4, 2025

Summary

  • Modernize and polish header/home start page styling
  • Add home-specific header behavior (HostBinding for isHome)
  • Emit search query updates from header component
  • Replace legacy toolbar dependency with local SCSS (.modern-header)
  • Improve header visuals: gradients, glow, ambient layers, brand block, pulsing logo
  • Cleanup: remove unused MatToolbarModule import and unused module entry

Changes

  • Header:
    • Add HostBinding to toggle home-header class based on isHome
    • Expose searchQuery output and emit updates via onSearchQueryUpdate
    • Rewrite SCSS for modern header and separate home-specific styles
    • Refactor imports and remove MatToolbarModule from module list
  • UX polish:
    • Adjust toolbar sizing, brand block, logo animation, and responsive tweaks
    • Improve visual depth, hover states, shadows, and pointer handling

Why

  • Provide a distinct, polished start/home appearance while keeping header behavior pluggable
  • Remove unused Angular Material toolbar dependency in favor of local styling
  • Allow parent components to react to user search input via emitted events

Notes

  • Related UI improvements included for recent-playlists, empty-state, and add-playlist menu in the same scope of styling/UX updates

Summary by CodeRabbit

  • New Features

    • Search functionality integrated into app header
    • Add playlist dialog with multiple import options
    • Welcome and empty state screens with feature highlights
    • Copy URL to clipboard for playlist export
    • macOS-specific window enhancements
  • UI/UX Improvements

    • Modernized header design with improved layout
    • Enhanced empty state animations and visuals
    • Better responsive design for smaller screens
  • Documentation

    • Angular coding standards guide added

✏️ Tip: You can customize this high-level summary in your review settings.

@vercel
Copy link

vercel bot commented Dec 4, 2025

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Preview Comments Updated (UTC)
iptvnator Error Error Dec 6, 2025 8:47pm

@coderabbitai
Copy link

coderabbitai bot commented Dec 4, 2025

Important

Review skipped

Auto reviews are disabled on base/target branches other than the default branch.

Please check the settings in the CodeRabbit UI or the .coderabbit.yaml file in this repository. To trigger a single review, invoke the @coderabbitai review command.

You can disable this status message by setting the reviews.review_status to false in the CodeRabbit configuration file.

Note

.coderabbit.yaml has unrecognized properties

CodeRabbit is using all valid settings from your configuration. Unrecognized properties (listed below) have been ignored and may indicate typos or deprecated fields that can be removed.

⚠️ Parsing warnings (1)
Validation error: Unrecognized key(s) in object: 'auto_review'
⚙️ Configuration instructions
  • Please see the configuration documentation for more information.
  • You can also validate your configuration using the online YAML validator.
  • If your editor has YAML language server enabled, you can add the path at the top of this file to enable auto-completion and validation: # yaml-language-server: $schema=https://coderabbit.ai/integrations/schema.v2.json

Walkthrough

This PR introduces macOS platform support, redesigns the header with modern styling and a new add-playlist menu component, refactors recent playlists UI with empty states, creates new standalone Angular components (AddPlaylistMenuComponent, EmptyStateComponent), restructures internationalization files across 12+ languages with new sections (SETTINGS, THEMES, CHANNELS, EPG, PORTALS, LANGUAGES), and updates component patterns to use signals and new Angular input/output APIs.

Changes

Cohort / File(s) Summary
Documentation & Configuration
CLAUDE.md, apps/web/project.json
Added Angular coding standards documentation; increased anyComponentStyle budget from 8kb to 10kb for production and pwa configurations.
macOS Platform Support
apps/electron-backend/src/app/app.ts, apps/web/src/app/app.component.ts, apps/web/src/styles.scss
Added macOS-specific window chrome configuration (titleBarStyle, titleBarOverlay), exposed isMacOS platform flag via HostBinding, and added macOS-scoped CSS padding adjustments.
Header Component Redesign
apps/web/src/app/shared/components/header/header.component.html, header.component.scss, header.component.ts
Replaced legacy mat-toolbar with modern header structure featuring branded logo block with pulse animation, conditional search bar for home view, and refactored add-playlist action to use new AddPlaylistMenuComponent; extensive styling overrides including glass-morphism effects, animations, responsive breakpoints, and Material icon customizations.
Add Playlist Menu Component
libs/ui/components/src/lib/add-playlist-menu/*
Created new standalone component with five playlist type options (file, url, text, xtream, stalker), mat-menu integration, and playlistTypeSelected output emitter; exported in barrel index.
Recent Playlists Component
libs/ui/components/src/lib/recent-playlists/recent-playlists.component.html, recent-playlists.component.scss, recent-playlists.component.ts
Refactored to use input-based searchQueryInput and new playlistsData$ stream combining playlists with totalCount; added addPlaylistClicked output; removed search input UI and onSearchQueryUpdate/onSearchHotkey handlers; integrated EmptyStateComponent.
Empty State Component
libs/ui/components/src/lib/recent-playlists/empty-state/*
Created new standalone component with dual-state rendering (welcome illustration with feature list vs. no-results state); includes AddPlaylistMenuComponent integration and comprehensive animations/styling for welcome and search-failure states.
Playlist Item & Info Components
libs/ui/components/src/lib/recent-playlists/playlist-item/playlist-item.component.scss, playlist-info/playlist-info.component.html, playlist-info/playlist-info.component.ts
Enhanced playlist-item with hover effects, improved status indicators, and responsive styling; added copy-to-clipboard URL functionality in playlist-info with snackbar feedback.
Home Component
apps/web/src/app/home/home.component.html, home.component.scss, home.component.ts
Added MatDialog dependency, searchQuery signal, onSearchQueryChange/onAddPlaylist handlers, and wired header searchQuery output and recent-playlists addPlaylistClicked input; updated recent-playlists height calculation.
Internationalization Restructuring
apps/web/src/assets/i18n/{ar,ary,by,de,en,es,fr,ja,ko,nl,pl,pt,ru,tr,zhtw}.json
Massive i18n reorganization introducing new top-level sections (SETTINGS, THEMES, CHANNELS, TOP_MENU, EPG, LANGUAGES, PORTALS, ABOUT) with nested content previously scattered across root or HOME blocks; restructured content varies by language but follows consistent modular patterns; added welcome/feature/no-results strings and expanded error/dialog messaging.
Public Exports
libs/ui/components/src/index.ts
Added barrel export for new AddPlaylistMenuComponent.

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~60 minutes

  • i18n consistency across 15 language files: While restructuring patterns are similar, verifying structural alignment and translation completeness across all languages requires careful cross-file validation
  • Component signal/input/output patterns: Verify proper Angular 16+ patterns in new components (AddPlaylistMenuComponent, EmptyStateComponent) and refactored recent-playlists
  • Empty state conditional logic: Ensure welcome/no-results states render correctly based on playlists.empty and totalCount conditions
  • Header styling complexity: Extensive CSS including glass-morphism effects, animations (fadeIn, slideUp, gridMove), responsive breakpoints (480px, 599px, 899px), and Material icon overrides via ::ng-deep
  • Platform detection and macOS-specific logic: Verify isMacOS binding, platform-specific window chrome, and CSS padding adjustments work correctly

Possibly related PRs

  • fix/m3u-auto-refresh-mechanism #648: Modifies recent-playlists UI components (playlist-item styles and playlist list behavior), indicating parallel work on the same component area.

Poem

🐰 A header blooms with modern grace,
Playlists welcome with open space,
New menus dance, translations gleam,
Empty states now live the dream,
macOS joins the hoppy team! 🎯✨

Pre-merge checks and finishing touches

✅ Passed checks (3 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title 'style/improve-start-page' accurately describes the main scope of the PR, which focuses on styling improvements to the home page start page and header components.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

@nx-cloud
Copy link

nx-cloud bot commented Dec 4, 2025

View your CI Pipeline Execution ↗ for commit 3e2afe1

Command Status Duration Result
nx run electron-backend:make ✅ Succeeded 10m 18s View ↗
nx build electron-backend ✅ Succeeded 36s View ↗

☁️ Nx Cloud last updated this comment at 2025-12-06 21:00:55 UTC

@4gray
Copy link
Owner Author

4gray commented Dec 5, 2025

@coderabbitai review

@coderabbitai
Copy link

coderabbitai bot commented Dec 5, 2025

✅ Actions performed

Review triggered.

Note: CodeRabbit is an incremental review system and does not re-review already reviewed commits. This command is applicable only when automatic reviews are paused.

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 7

🧹 Nitpick comments (9)
libs/ui/components/src/lib/recent-playlists/recent-playlists.component.scss (1)

16-16: Align .meta color with app theme rather than OS prefers-color-scheme

prefers-color-scheme: light may diverge from the app’s own dark/light theme (e.g., user selects dark theme while OS is light). Consider driving .meta color via your existing theme classes or CSS variables instead of the OS media query, so typography stays consistent with the selected app theme.

Also applies to: 25-30

CLAUDE.md (1)

147-217: Modern Angular guidance is solid; consider adding version/legacy notes

The signal-based recommendations for queries, inputs/outputs, and control flow look correct and match current Angular patterns. To avoid confusion, you might briefly note the minimum Angular version these APIs require and that older parts of the codebase may still legitimately use decorator-based patterns until fully migrated.

If helpful, double-check your workspace’s Angular version and ensure all projects are on a version that supports viewChild(), input(), output(), and the @if/@for template syntax before enforcing this section strictly.

libs/ui/components/src/lib/recent-playlists/playlist-info/playlist-info.component.html (1)

55-70: URL copy button wiring looks good; consider adding aria-label

The suffix icon button correctly calls copyUrl() and avoids interfering with form submission. For better accessibility, consider adding an explicit ARIA label, e.g.:

<button
  mat-icon-button
  matSuffix
  type="button"
  (click)="copyUrl()"
  [matTooltip]="'HOME.PLAYLISTS.INFO_DIALOG.COPY_URL' | translate"
  [attr.aria-label]="'HOME.PLAYLISTS.INFO_DIALOG.COPY_URL' | translate"
>
  <mat-icon>content_copy</mat-icon>
</button>
apps/web/src/app/app.component.ts (1)

1-2: Tighten isMacOS HostBinding to explicitly return a boolean

The platform check is fine, but it’s worth making the getter explicitly boolean and slightly more defensive:

@HostBinding('class.macos-platform') get isMacOS(): boolean {
  return !!(
    typeof navigator !== 'undefined' &&
    navigator.platform?.toLowerCase().includes('mac') &&
    (window as any).electron
  );
}

This keeps the CSS class binding unambiguous and avoids any non-boolean values leaking through the HostBinding.

Also applies to: 30-32

libs/ui/components/src/lib/recent-playlists/empty-state/empty-state.component.html (1)

1-87: Empty-state flows are well structured; consider aria-hiding decorative SVGs

The welcome vs no-results branching, integration with app-add-playlist-menu, and onAddPlaylist($event) hookup all look consistent and should work as intended for both first-run and filtered-empty states.

Since the SVGs are decorative, you might want to explicitly hide them from assistive tech:

<svg
  class="illustration"
  viewBox="0 0 512 512"
  xmlns="http://www.w3.org/2000/svg"
  aria-hidden="true"
  focusable="false"
>
  ...
</svg>

Same idea for the smaller no-results illustration.

libs/ui/components/src/lib/recent-playlists/recent-playlists.component.html (1)

3-15: Playlist empty-state gating and data binding look correct

Using data.playlists.length plus data.totalCount to choose between the welcome and no-results empty states is a good separation of first-run vs filtered-empty UX, and the switch to data.playlists in the @for loop is consistent with that model.

You can optionally remove let last = $last from the @for loop since it’s not used anymore, to keep the template slightly cleaner.

Also applies to: 34-38, 48-49

libs/ui/components/src/lib/recent-playlists/empty-state/empty-state.component.scss (1)

24-24: Consider using CSS variables for color values.

Hardcoded color values like #3b82f6, #60a5fa, #2563eb appear throughout the file. Using CSS variables (custom properties) would improve maintainability, enable easier theming, and reduce duplication.

Example approach:

:root {
  --color-primary: #3b82f6;
  --color-primary-light: #60a5fa;
  --color-primary-dark: #2563eb;
}

.title {
  background: linear-gradient(135deg, var(--color-primary-light) 0%, var(--color-primary) 50%, var(--color-primary-dark) 100%);
  // ...
}

This would centralize color definitions and make future theme adjustments simpler.

Also applies to: 54-75, 100-102, 144-144

apps/web/src/assets/i18n/ko.json (1)

1-254: Good restructuring; verify incomplete translations.

The Korean i18n file has been successfully restructured to match the modular pattern. However, there are a few English fallback strings that may need Korean translations:

  • Line 10: "Import as text"
  • Line 91: "Show subtitles"
  • Line 138: "Open Multi-EPG view"
  • Line 143-144: "Live now", "Live stream"
  • Line 181-192: Several entries in MENU section

These may be intentional or may need translation updates.

apps/web/src/app/shared/components/header/header.component.scss (1)

399-474: Consider CSS custom properties to reduce color duplication.

The styling quality is excellent, but the repeated rgba color values throughout the file could benefit from CSS custom properties for maintainability.

Consider defining color variables at the top:

:host {
    --header-text: rgba(255, 255, 255, 0.95);
    --header-text-dim: rgba(255, 255, 255, 0.85);
    --header-border: rgba(255, 255, 255, 0.06);
    --accent-purple: rgba(139, 92, 246, 1);
    --accent-purple-dim: rgba(139, 92, 246, 0.85);
    // ... etc
}

Then use them throughout:

.search-icon {
    color: var(--header-text-dim);
}
📜 Review details

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between c2b1220 and 02561a2.

📒 Files selected for processing (38)
  • CLAUDE.md (1 hunks)
  • apps/electron-backend/src/app/app.ts (1 hunks)
  • apps/web/project.json (2 hunks)
  • apps/web/src/app/app.component.ts (2 hunks)
  • apps/web/src/app/home/home.component.html (1 hunks)
  • apps/web/src/app/home/home.component.scss (1 hunks)
  • apps/web/src/app/home/home.component.ts (2 hunks)
  • apps/web/src/app/shared/components/header/header.component.html (2 hunks)
  • apps/web/src/app/shared/components/header/header.component.scss (1 hunks)
  • apps/web/src/app/shared/components/header/header.component.ts (2 hunks)
  • apps/web/src/assets/i18n/ar.json (1 hunks)
  • apps/web/src/assets/i18n/ary.json (1 hunks)
  • apps/web/src/assets/i18n/by.json (1 hunks)
  • apps/web/src/assets/i18n/de.json (2 hunks)
  • apps/web/src/assets/i18n/en.json (3 hunks)
  • apps/web/src/assets/i18n/es.json (1 hunks)
  • apps/web/src/assets/i18n/fr.json (1 hunks)
  • apps/web/src/assets/i18n/ja.json (1 hunks)
  • apps/web/src/assets/i18n/ko.json (1 hunks)
  • apps/web/src/assets/i18n/nl.json (1 hunks)
  • apps/web/src/assets/i18n/pl.json (1 hunks)
  • apps/web/src/assets/i18n/pt.json (1 hunks)
  • apps/web/src/assets/i18n/ru.json (2 hunks)
  • apps/web/src/assets/i18n/tr.json (1 hunks)
  • apps/web/src/assets/i18n/zhtw.json (1 hunks)
  • apps/web/src/styles.scss (1 hunks)
  • libs/ui/components/src/index.ts (1 hunks)
  • libs/ui/components/src/lib/add-playlist-menu/add-playlist-menu.component.html (1 hunks)
  • libs/ui/components/src/lib/add-playlist-menu/add-playlist-menu.component.ts (1 hunks)
  • libs/ui/components/src/lib/recent-playlists/empty-state/empty-state.component.html (1 hunks)
  • libs/ui/components/src/lib/recent-playlists/empty-state/empty-state.component.scss (1 hunks)
  • libs/ui/components/src/lib/recent-playlists/empty-state/empty-state.component.ts (1 hunks)
  • libs/ui/components/src/lib/recent-playlists/playlist-info/playlist-info.component.html (1 hunks)
  • libs/ui/components/src/lib/recent-playlists/playlist-info/playlist-info.component.ts (4 hunks)
  • libs/ui/components/src/lib/recent-playlists/playlist-item/playlist-item.component.scss (6 hunks)
  • libs/ui/components/src/lib/recent-playlists/recent-playlists.component.html (3 hunks)
  • libs/ui/components/src/lib/recent-playlists/recent-playlists.component.scss (2 hunks)
  • libs/ui/components/src/lib/recent-playlists/recent-playlists.component.ts (6 hunks)
🧰 Additional context used
🧬 Code graph analysis (2)
libs/ui/components/src/lib/recent-playlists/recent-playlists.component.ts (1)
apps/web/src/app/shared/components/add-playlist/add-playlist-dialog.component.ts (1)
  • PlaylistType (21-21)
apps/web/src/app/home/home.component.ts (1)
apps/web/src/app/shared/components/add-playlist/add-playlist-dialog.component.ts (1)
  • PlaylistType (21-21)
🔇 Additional comments (40)
apps/web/project.json (1)

43-43: The 2kb budget increase is justified by the extensive header styling.

The header component's 522-line SCSS file includes legitimate styling additions: ambient glow animations (headerAmbience, logoGlow keyframes), glass-morphism effects, detailed state transitions (hover, focus, active), gradients, Material Design overrides, and responsive breakpoints. This scope reasonably accounts for the 10kb limit. The warning threshold remains at 4kb, providing adequate early feedback for future growth.

apps/web/src/styles.scss (1)

4-15: macOS-specific spacing is well-scoped and non-invasive

The new padding rules are narrowly scoped to app-root.macos-platform and should only affect the intended macOS layout without impacting other platforms.

apps/web/src/assets/i18n/de.json (1)

61-68: New HOME playlist onboarding/empty-state strings look consistent

The added WELCOME_* and NO_RESULTS_* keys under HOME.PLAYLISTS and the simplified SETTINGS.TITLE are consistent with the structure used in other locales and should integrate cleanly with the new home UI.

Also applies to: 196-196

apps/electron-backend/src/app/app.ts (1)

82-87: macOS window chrome options are correctly gated

The titleBarStyle: 'hidden' and titleBarOverlay: true options are cleanly guarded by the darwin platform check and won’t affect other platforms; the spread placement within the options object is safe.

If you haven’t already, quickly confirm against the Electron version in use that titleBarOverlay: true with titleBarStyle: 'hidden' matches the visual you want on macOS (color/height of the overlay can be tuned further if needed).

apps/web/src/assets/i18n/ru.json (1)

18-25: Russian onboarding/empty-state additions are consistent and clear

The new WELCOME_* and NO_RESULTS_* playlist messages read well and match the new home UX semantics, and simplifying SETTINGS.TITLE to just “Настройки” is appropriate for UI labels.

Also applies to: 126-126

apps/web/src/assets/i18n/by.json (1)

1-286: LGTM! Clean i18n restructuring.

The Belarusian translation file has been successfully restructured into a modular format with proper nesting. All translation values appear complete and consistent with the PR's i18n refactoring pattern.

apps/web/src/assets/i18n/tr.json (1)

1-306: LGTM! Comprehensive Turkish translations.

The Turkish translation file has been successfully restructured with all sections properly translated. The file includes additional features like remote control settings and CORS notes, all with complete Turkish translations.

apps/web/src/assets/i18n/ary.json (1)

1-318: LGTM! Complete Moroccan Arabic translations.

The Moroccan Arabic (Darija) translation file is well-structured with comprehensive translations including newer features like sorting options and playlist export feedback. All values are properly translated.

apps/web/src/app/home/home.component.scss (1)

1-4: LGTM! Height calculation adjusted for new header.

The height calculation has been updated from calc(100vh - 100px) to calc(100vh - 71px), providing 29px more vertical space for the recent playlists area. This aligns with the PR's header modernization and toolbar sizing improvements.

libs/ui/components/src/lib/add-playlist-menu/add-playlist-menu.component.html (1)

1-43: LGTM! Well-structured menu component.

The add-playlist menu template is well-implemented with:

  • Proper Material Design components and patterns
  • Good accessibility via aria-labels
  • Consistent internationalization using translation pipe
  • Semantic icons for each action type
  • Logical grouping with divider separating standard uploads from specialized portals
libs/ui/components/src/index.ts (1)

1-1: LGTM! Public API export added.

The new AddPlaylistMenuComponent has been properly exported through the barrel index, making it available as part of the public UI components library API. The export follows the established pattern and is correctly positioned.

apps/web/src/app/home/home.component.html (1)

1-10: Search and add-playlist wiring between header and recent playlists looks correct

The header’s searchQuery output feeding a searchQuery signal and then into app-recent-playlists, plus the addPlaylistClicked handler, forms a clear and consistent data flow. No issues from this template change.

libs/ui/components/src/lib/recent-playlists/playlist-info/playlist-info.component.ts (1)

1-1: Clipboard-based URL copy is correctly implemented; optional failure feedback

The clipboard integration is wired properly:

  • ClipboardModule is imported, and Clipboard is injected.
  • copyUrl() safely reads the url control, guards on a truthy value, and only shows a snackbar when clipboard.copy(url) reports success.

If you want to improve UX further, you could also surface feedback when there is no URL or when the copy call fails (e.g., show a brief error snackbar), but the current behavior is already safe and functional.

Also applies to: 11-11, 17-17, 36-47, 50-50, 225-240

apps/web/src/app/home/home.component.ts (1)

1-6: Home search signal and add-playlist dialog handlers are well wired

Using a signal<string> for searchQuery and updating it via onSearchQueryChange fits nicely with the searchQuery() binding in the template. The onAddPlaylist handler opening the add-playlist dialog with a PlaylistType payload is also consistent with the rest of the flow.

Also applies to: 14-31

apps/web/src/app/shared/components/header/header.component.ts (4)

39-41: LGTM! Clean HostBinding pattern for conditional styling.

The use of @HostBinding with a getter to toggle the home-header class based on the isHome property is idiomatic and allows for clean separation between home and non-home header styling.


54-54: LGTM! Clean use of Angular's modern output API.

The searchQuery output is properly typed and enables parent components to react to search input changes, which aligns with the PR's goal of making the header more pluggable.


167-169: LGTM! Clean event emission pattern.

The onSearchQueryUpdate method provides a clear interface for emitting search query changes, following Angular conventions with appropriate typing.


50-50: Add explicit type for better type safety.

The addPlaylistMenuComponent is currently typed as any, which loses type safety benefits. The return type of viewChild.required should be explicitly typed.

Apply this diff to add the proper type:

-    readonly addPlaylistMenuComponent = viewChild.required(AddPlaylistMenuComponent);
+    readonly addPlaylistMenuComponent = viewChild.required<AddPlaylistMenuComponent>(AddPlaylistMenuComponent);

Or alternatively, let TypeScript infer the type by removing the explicit any annotation if it exists in your source.

Likely an incorrect or invalid review comment.

libs/ui/components/src/lib/recent-playlists/empty-state/empty-state.component.scss (1)

1-486: Excellent comprehensive styling with modern CSS patterns.

The styling demonstrates:

  • Smooth animations that enhance UX (fadeIn, slideUp, floatIn, gridMove)
  • Comprehensive responsive design with multiple breakpoints (max-width: 480px, max-height: 700px, 550px)
  • Thoughtful light theme support via @media (prefers-color-scheme: light)
  • Clear organization and naming conventions

The implementation creates a polished, modern UI for the empty state component.

apps/web/src/assets/i18n/pl.json (1)

1-318: LGTM! Well-organized i18n restructuring.

The Polish translations have been successfully reorganized into a hierarchical structure with clear top-level sections (HOME, SETTINGS, THEMES, CHANNELS, TOP_MENU, EPG, etc.). This modular approach improves maintainability and aligns with the broader i18n restructuring across other language files in the PR.

libs/ui/components/src/lib/recent-playlists/playlist-item/playlist-item.component.scss (1)

1-185: LGTM! Polished styling improvements for playlist items.

The updates enhance the playlist item UI with:

  • Smooth transitions using cubic-bezier easing functions
  • Improved hover states for both dark and light themes
  • Enhanced drag-and-drop visual feedback with layered shadows
  • Refined action button interactions with scale transforms and opacity transitions
  • Proper status indicators with glowing effects
  • Thoughtful responsive behavior that hides secondary icons on mobile

These changes align well with the PR's goal of modernizing and polishing the UI.

apps/web/src/assets/i18n/nl.json (1)

1-318: LGTM! Consistent i18n restructuring.

The Dutch translations follow the same hierarchical restructuring pattern as other language files in the PR, with clear modular sections. The organization improves maintainability and provides a consistent structure across all supported languages.

libs/ui/components/src/lib/add-playlist-menu/add-playlist-menu.component.ts (2)

7-7: LGTM! Well-defined type for playlist variants.

The PlaylistType union type clearly defines the supported playlist types and is appropriately exported for use by consuming components like HeaderComponent and EmptyStateComponent.


9-22: LGTM! Clean, reusable component design.

The AddPlaylistMenuComponent demonstrates excellent component design:

  • Standalone architecture with focused imports
  • Modern Angular APIs (viewChild.required, output)
  • Clear single responsibility (menu presentation and type selection)
  • Proper typing with generic parameters
  • Reusable across multiple contexts (header, empty state)

The implementation is clean and follows Angular best practices.

libs/ui/components/src/lib/recent-playlists/empty-state/empty-state.component.ts (2)

8-8: LGTM! Clear type definition for empty states.

The EmptyStateType union type clearly distinguishes between the 'welcome' state (first-time user) and 'no-results' state (search/filter returned nothing), making the component's API intuitive.


10-24: LGTM! Well-structured component with proper composition.

The EmptyStateComponent demonstrates good component design:

  • Proper composition with AddPlaylistMenuComponent via viewChild
  • Required input ensures the component always has a defined state
  • Type-safe output that matches the PlaylistType from the menu component
  • Clean integration pattern that promotes reusability

The component follows Angular best practices and integrates cleanly with the new menu component.

apps/web/src/assets/i18n/en.json (3)

18-25: LGTM! Welcome onboarding strings enhance UX.

The new welcome messages and feature highlights provide clear guidance for first-time users. The copy is professional and informative.


56-58: LGTM! URL copy functionality strings are clear.

The new translation keys for URL clipboard operations are concise and provide appropriate user feedback.


128-128: LGTM! Settings title simplification.

Removing the application name suffix from the settings title is cleaner and follows common UI patterns.

libs/ui/components/src/lib/recent-playlists/recent-playlists.component.ts (4)

59-76: LGTM! Clean refactor from ViewChild to signal-based input.

The migration from ViewChild-based search query binding to an input signal with a constructor effect is a good modernization. The effect properly syncs the input to the internal BehaviorSubject.


61-61: LGTM! New output enables parent component communication.

The new addPlaylistClicked output properly enables the parent component to react to add-playlist menu selections.


155-157: LGTM! Simple delegation to output.

The onAddPlaylist method correctly emits the playlist type through the output.


78-122: Verify template and consumer compatibility with playlistsData$ structure change.

The renamed playlistsData$ now emits an object containing both playlists and totalCount instead of just the playlists array. This is a breaking change for the template and any consumers.

This issue requires manual verification as the specific component file path and template cannot be located in the repository. To properly validate the breaking change claim, please verify:

  1. That the template correctly accesses the new structure (playlistsData$ | async as data then uses data.playlists and data.totalCount)
  2. That any parent components or other consumers consuming this component through an input binding have been updated to handle the new observable structure
  3. Whether the original code previously returned just the array directly and this change genuinely breaks existing consumers
apps/web/src/app/shared/components/header/header.component.scss (6)

6-35: LGTM! Clean modern header foundation.

The .modern-header provides a solid foundation with proper flexbox layout, Electron drag region support, and subtle depth effects.


37-87: LGTM! Elegant home-header ambient effects.

The home-header variant with animated ambient glow creates a polished, distinctive appearance. The headerAmbience animation is smooth and subtle.


89-132: LGTM! Glass-morphism brand block is well-executed.

The brand block styling with backdrop-filter, subtle borders, and hover transitions creates an elegant glass effect. The home-header variant with purple accents fits the design system.


227-284: LGTM! Search container glass-morphism with great focus states.

The search container has excellent focus-within states with proper visual feedback. The purple accent on home-header maintains consistency. Transitions are smooth and accessible.


477-522: LGTM! Well-considered responsive breakpoints.

The responsive adjustments at 899px and 599px appropriately scale down the header for smaller screens while maintaining readability and usability.


227-338: The search input text color rgba(255, 255, 255, 0.95) on the dark background #131316 produces an effective contrast ratio of approximately 16.7:1, which far exceeds the WCAG AA requirement of 4.5:1 for normal text. No contrast compliance issue exists with the search input text.

Likely an incorrect or invalid review comment.

apps/web/src/assets/i18n/ja.json (1)

1-306: LGTM! Consistent restructuring across locales.

The Japanese i18n file follows the same hierarchical restructuring as the French file, maintaining consistency across locales. The Japanese translations are preserved while adopting the new modular structure.

Note: The verification script for fr.json will also validate usage of keys in this file.

4gray added 16 commits December 6, 2025 21:44
Enhance the header component to support a distinct "home" appearance
and emit search updates. Add a HostBinding that toggles a home-header
class from the isHome flag so styles can target the home state.
Expose a searchQuery output and wire an onSearchQueryUpdate method to
emit the search text, enabling parent components to react to user
searches.
Refactor imports to include HostBinding and output. Tidy toolbar metrics
and adjust element sizing for a compact brand block and pulsing logo.
Introduce comprehensive SCSS for the home header:
- gradient background, animated glow overlay, and edge accent
- brand block styling with blur, border, hover states and box-shadow
- logo sizing, pulse animation and responsive tweaks
- reduced toolbar height and overall visual polish
These changes separate home-specific styling from the default header
appearance and provide a programmatic hook for search interactions.
Update header component UI and streamline imports.

- Remove MatToolbarModule import and module list entry
  because the toolbar styling is handled by local SCSS and the
  Angular Material toolbar is no longer required.
- Rewrite header SCSS to introduce a .modern-header wrapper with
  consistent sizing, padding, alignment and a subtle bottom border.
- Add layered ambient and depth effects: refined ::before ambient
  gradient (headerAmbience), ::after bottom accent, and adjusted
  keyframes for a gentler motion.
- Refine home-header styles to target .modern-header and tune colors
  and gradients for a cohesive dark theme.
- Rework .brand-block visuals: lighter glass effect, adjusted
  radii, blur, borders, hover transform, and shadowing for a modern
  elevated look.
- Minor cleanup: remove legacy variables and comments; improve
  box-sizing, layout, and pointer-event handling to ensure expected
  interaction regions.

These changes modernize the header's visual design, improve layout
consistency across pages, and remove an unnecessary module import.
Update recent playlists styles to improve visuals, hover feedback,
and theme adaptability. Key changes:
- Hide horizontal overflow on playlists list to avoid scroll bleed.
- Add rounded corners, subtle transitions, and hover background for
  mat-list-item; include light theme hover variant.
- Reduce drag preview radius, replace shadow with layered shadows,
  increase opacity, and extend drag animation duration for smoother
  interactions.
- Adjust responsive selector formatting.
- Add transitions and hover scaling to action buttons, plus light
  theme variant; improve icon opacity transitions.
- Improve icon container behavior and upload-type-icon visibility on
  hover.
- Restyle status dot and state shadows, tweak unavailable color.
- Restyle auto-refresh indicator with shadow, rotation on hover, and
  light theme background.
- Minor spacing and layout tweaks across SCSS.

Code imports:
- Add Clipboard and ClipboardModule import and include MatIconButton
  and MatTooltip references in playlist-info component to support new
  copy/tooltip UI affordances.

These changes enhance UX polish, accessibility of interactive affordances,
and light/dark theme consistency.
- Shorten German settings TITLE from "Einstellungen / IPTVnator" to
  "Einstellungen" to remove redundant app name and keep UI labels concise.
- Reformat and normalize Korean i18n JSON indentation and structure to
  match expected layout (consistent nesting and whitespace).
- Reintroduce missing HOME -> nested sections (TABS, PLAYLISTS,
  FILE_UPLOAD, URL_UPLOAD, TEXT_IMPORT, STALKER_PORTAL, XTREAM_PLAYLIST)
  in ko.json to restore previously collapsed keys and ensure all keys
  are present for runtime lookup.
- Fix several untranslated/placeholder labels and ensure key presence
  for dialogs, validations and UI strings so translations load
  consistently across components.
Add new strings for the PLAYLIST view across English,
Spanish, French, German, and translations. The additions include a
welcome title description, a prompt to the first playlist, feature
labels for supported playlist types (MU/M3U, Xtream Codes Stalker),
and "no results title and description to clarify search/filter
.

These changes improve the onboarding experience new users and giveclearer feedback when searches return no. They also
ize feature labels across languages to communicate
supported playlist formats
Add a new EmptyState component and template for the recent-playlists
widget, providing two visual states: "welcome" and "no-results".

- Create empty-state.component.html with:
  - a welcome illustration (monitor + WiFi) and content for first-time
    users, including translated title/description, add-playlist action
    button and features list.
  - a no-results illustration (magnifying glass + box) and compact
    content for empty search/results.
  - conditional rendering based on type() to switch states.

- Start empty-state.component.ts with type definition and imports for
  Angular Material and translation; wire up AddPlaylistMenu types.

This implements the UI for when there are no recent playlists and
provides the primary CTA to add the first playlist, improving onboarding
and empty-state UX.
Raise the maximumError for anyComponentStyle from 8kb to
kb in the web app build configuration. This relaxes the
build-size enforcement for component styles to accommodate
slightly larger CSS bundles and avoid spurious build failures.
Introduce a reusable AddPlaylistMenuComponent that provides a Material
menu with options to add playlists via file, URL, text, Xtream or Stalker
portal. Define a PlaylistType union and expose a playlistTypeSelected
output so parent components can react to the selected import type.

- Add component TypeScript with Angular metadata and required Material
  imports.
- Add template with accessible menu items, icons, translation keys and
  click handlers that emit the selected PlaylistType.
- Organize menu items with a divider to separate common file/URL/text
  options from provider-specific imports.

This adds a focused UI building block for playlist import flows and
standardizes how import type selection is communicated to parent scopes.
Introduce explicit empty-state handling in RecentPlaylists:
- Replace previous direct rendering of an empty mat-list item with
  app-empty-state for two cases: a global "welcome" state when no
  playlists exist at all, and a "no-results" state when filters/search
  return nothing. This clarifies UX and provides a CTA for adding
  playlists in the welcome state.
- Change playlist data binding from playlists$ to playlistsData$ and
  adapt loops and accessors to data.playlists / data.totalCount.
- Keep existing global favorites item and playlist-item rendering.

Wire up addPlaylist event and components:
- Add addPlaylistClicked output to RecentPlaylists component and
  forward the event from the home component so the parent can open
  the add-playlist flow.
- Import EmptyStateComponent and PlaylistType types used by the new
  output.

Minor cleanup and imports:
- Reformat some imports and add tap to RxJS imports.
- Adjust template structure and placeholders for deferred loading.
Add macOS-specific title bar settings to the Electron main window
creation so the app uses a hidden title bar with an overlay on Darwin.
This ensures a more native, modern appearance on macOS while keeping
existing minimum size and saved bounds behavior unchanged.
Add app-region: drag to container and header elements and app-region:
no-drag to interactive controls multiple components so the
Tauri window dragging behaves correctly while keeping buttons and form
controls clickable. Expand header search max width from 500px to 800px
to give more room on larger screens. Clean up and restyle video-player
toolbar toolbar primary colors and unify toolbar spacing.

Files changed include navigation, sidebar, header, main containers,
live-stream layout, navigation-bar, stalker container, and video-player
toolbar. These changes improve window drag UX on desktop and refine
toolbar/header appearance.
Add new English keys for remote control URL and QR code to support
remote-control features in the settings UI. Extend French locale with
many missing and corrected translations: add "Playlists" root entry,
Xtream/Stalker import labels, UI copy improvements (e.g. "Chaînes",
grammar fixes), new playlist export/copy messages, search/auto-refresh
labels, and removal success message. Fix several typos and phrasing in
French strings (IPTV, chaînes, ajouter(e), requièrent).

These changes enable new remote-control functionality and improve UX
for French users by completing and correcting the translations.
Add an isElectron flag to PlaylistItemComponent and conditionally
render the refresh button only when running inside Electron.
This prevents exposing the server refresh action in non-Electron
(environments like the browser) where window.electron is unavailable
and the feature is not supported.

Update ensures safer behavior by checking !!window.electron in the
component and using that value in the template to guard the UI.
Add support for displaying local remote-control URLs and QR code in the
Settings UI, including styles for URL list, row layout, monospaced links,
and a QR container. Expose a new global API signature getLocalIpAddresses
for retrieving local IPs.

Fix several UI issues:
- Correct typo in header method name (opedAddPlaylistDialog -> openAddPlaylistDialog).
- Fix malformed GitHub URL and collapse img tag formatting.
- Reformat imports and viewChild usage for readability.

Change local development backend URL to localhost:3000 in the local
environment to point to the running local API during development.

These changes improve developer ergonomics (local backend), add a remote
control discovery UX for users on the same network, and tidy up header
bugs and formatting.
@4gray 4gray force-pushed the style/improve-start-page branch from 68005ae to 3e2afe1 Compare December 6, 2025 20:46
@4gray 4gray merged commit 6b0436e into nx Dec 6, 2025
6 of 7 checks passed
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.

2 participants