docs: remove old implementation docs and setup guides

This commit is contained in:
Bruno Charest 2025-10-14 13:19:45 -04:00
parent 32a9998b40
commit 5a95b33081
23 changed files with 7186 additions and 0 deletions

View File

@ -35,6 +35,7 @@ ObsiViewer offre une expérience de consultation en lecture seule dune voûte
- [ ] Modals dédition bookmarks - [ ] Modals dédition bookmarks
- Créer un `BookmarkEditorModal` (ajout/édition groupes et fichiers) - Créer un `BookmarkEditorModal` (ajout/édition groupes et fichiers)
- Le mode edition doit être inspiré de l'éditeur de gestion de notes Nimble Notes
- Valider les champs, support du parent selector, déplacement entre groupes - Valider les champs, support du parent selector, déplacement entre groupes
- Estimation : 2j - Estimation : 2j

View File

@ -0,0 +1,483 @@
# Prompt Windsurf — ObsiViewer Nimbus UI (Desktop + Mobile)
## 1. Project Overview and Core Philosophy
### 1.1. Product Philosophy
The redesign of the ObsiViewer application is guided by a set of core philosophical principles derived from a detailed analysis of the Nimbus Notes interface. These principles are not merely stylistic choices but foundational concepts that dictate the structure, flow, and user experience of the entire application. They ensure that the final product is not only visually similar to Nimbus Notes but also functionally and experientially aligned with its efficient, dense, and rapid workflow. The philosophy emphasizes a workspace-centric model, a dual-axis organizational system, a search-first approach to information retrieval, and a commitment to progressive disclosure to maintain a clean and focused user interface. Furthermore, it acknowledges the modern need for content to exist in multiple contexts, from private notes to public-facing portals, without friction. Adherence to these principles is paramount for achieving a successful and faithful reproduction of the target user experience.
#### 1.1.1. Workspace-First Architecture
The foundational principle of the interface is its **workspace-first** architecture. This concept dictates that all content—pages, folders, tags, and even team members—is contained within a strictly isolated and self-contained *workspace*. Switching between workspaces is not a simple global filter applied to a single, monolithic data set; rather, it is a complete context switch, transporting the user into an entirely new and distinct universe of content . This design choice has profound implications for the user experience. It allows for a high degree of organization and separation between different projects, teams, or personal and professional life, preventing the cognitive overload that can arise from a cluttered, undifferentiated information space. The interface must visually and functionally reinforce this separation, making it clear to the user which workspace they are currently operating in. The workspace selector, therefore, becomes a critical navigational element, and its implementation must be robust and easily accessible, as documented in the guides for navigating and managing workspaces . This architecture ensures that the user's mental model aligns perfectly with the application's data structure, leading to a more intuitive and less error-prone interaction.
#### 1.1.2. Bi-Axial Organization (Folders & Tags)
Complementing the workspace-first architecture is the **bi-axial organization** system, which employs two distinct but complementary methods for structuring content: **folders** and **tags**. Folders provide a traditional, hierarchical structure, allowing users to create a nested, tree-like organization that reflects a clear parent-child relationship between documents. This is ideal for creating a logical, top-down flow of information, such as organizing project documentation or a personal knowledge base. Tags, in contrast, offer a non-hierarchical, multi-categorical system for adding context and enabling rapid, cross-cutting discovery . A single page can be associated with multiple tags, allowing it to surface in various contexts regardless of its location within the folder hierarchy. For example, a project report could be tagged with `#quarterly-review`, `#marketing-strategy`, and `#client-xyz`, making it instantly discoverable through any of those lenses. The interface must support both systems seamlessly, providing clear visual distinctions and intuitive workflows for managing folders and tags. The guides on folders and tags provide a detailed look into how this dual system is intended to function, balancing rigid structure with flexible, associative context .
#### 1.1.3. Search-First, Navigate-Second
A core tenet of the user experience is the **"search first, navigate second"** philosophy. The interface is designed to prioritize rapid information retrieval through a powerful and always-visible search function, relegating manual navigation to a secondary role. The **top bar** is dominated by a large, centered search field, signaling its importance as the primary tool for interacting with the application's content. This is further enhanced by the use of **persistent filter chips**—"All folders," "All tags," and "All pages"—which provide immediate, at-a-glance feedback on the current search context . These chips are not static labels; they are interactive elements that allow users to refine their search scope on the fly without leaving their current workflow. The ability to see, edit, and reset these filters instantly makes the search process transparent and controllable. This approach caters to users who know what they are looking for and need to access it quickly, while still providing robust navigational tools for browsing and discovery. The design minimizes the cognitive load associated with finding information by making the most direct path—the search bar—the most prominent one.
#### 1.1.4. Progressive Disclosure
To maintain a clean and uncluttered interface despite the density of information and features, the design relies heavily on the principle of **progressive disclosure**. This strategy involves hiding advanced or less frequently used options until they are explicitly requested by the user. Instead of presenting a wall of controls, the interface reveals functionality contextually and on demand. Examples of this pattern include the **hover-reveal** of the subfolder creation button, which only appears when the user hovers over a parent folder, and the contextual panels like the **folder/tag picker** and the **document outline**, which are summoned via discrete triggers . This approach prevents the user from being overwhelmed by a complex interface, allowing them to focus on their primary task. It creates a sense of simplicity and elegance, even as it provides access to a powerful and feature-rich toolset. The goal is to make the application feel lightweight and approachable for new users while ensuring that power users can access advanced functionality without friction. This careful balance between simplicity and power is a hallmark of a well-designed user experience.
#### 1.1.5. Content with Multiple Facades (Portals)
The final philosophical pillar is the concept of **"one content, multiple facades,"** which is embodied by the **Portal** feature. This principle recognizes that a single piece of content, such as a project specification or a client report, often needs to be presented in different contexts with varying levels of access and branding. A page can be edited and managed within the private, internal environment of the ObsiViewer application, but it can also be seamlessly **published to an external, branded Portal** for sharing with clients, stakeholders, or the public . The commands for this action, such as **"Add to portal"** and **"Share,"** are consistently visible within the editor, making the transition from private creation to public dissemination a fluid and integrated part of the workflow . This eliminates the need for cumbersome export/import processes or separate content management systems for external-facing content. The interface must clearly communicate the publication status of a page and provide intuitive controls for managing its visibility and branding, effectively allowing a single source of truth to serve multiple audiences.
### 1.2. Core Principles for Redesign
To translate the high-level product philosophy into a concrete and actionable design, a set of eight core principles has been established. These principles serve as a checklist and a guide for every design and implementation decision, ensuring that the final ObsiViewer interface remains faithful to the spirit and functionality of the Nimbus Notes experience. They distill the complex interplay of layout, interaction, and workflow into a memorable and prescriptive set of rules. From the stability of the three-panel layout to the nuanced behavior of stateful filters and the seamless continuum between writing and publishing, these principles provide a clear roadmap for the development team. They are the "TL;DR" of the design specification, capturing the essence of what makes the Nimbus UI both powerful and intuitive.
#### 1.2.1. Three Stable Panels + Transient Overlays
The foundational layout of the application is built upon **three stable, persistent panels**: the left sidebar for primary navigation (folders and tags), the central column for the index or search results, and the right panel for the content reader/editor. This three-column structure provides a stable and predictable frame for the user's workflow, ensuring that primary navigational and contextual tools are always visible and accessible on a desktop screen. The stability of these panels creates a strong sense of place and orientation within the application. In contrast to these stable panels, more detailed or temporary interactions are handled through **transient overlays**, such as the floating pickers for folders and tags. These overlays appear on demand, provide a focused interface for a specific task (like filtering), and then disappear, returning the user to the stable three-panel view. This combination of a stable primary layout with transient secondary interactions is key to managing complexity without cluttering the main interface.
#### 1.2.2. Persistent Stateful Filters (Chips)
A key interaction pattern that must be meticulously reproduced is the use of **persistent, stateful filters**, visually represented as **chips**. Unlike simple, one-time-use dropdown menus, these chips are always visible in the central panel's header, providing continuous feedback on the current filtering state . They are "stateful" because they display the currently active filters (e.g., a specific folder or tag) and allow for immediate modification or removal. The presence of a **caret (▾)** and a **badge** (e.g., "+1") on these chips clearly communicates that they are interactive menus, not just static labels. This persistent visibility serves as a crucial piece of cognitive anchoring, reminding the user of their current context within the data and allowing them to refine their search without losing their place. The design must ensure these chips are not only visually distinct but also functionally robust, allowing for multi-selection and easy clearing of filters.
#### 1.2.3. Rich Pickers with Local Search
When a user interacts with one of the filter chips, they are presented with a **rich picker** interface. These are not standard browser dropdowns but sophisticated, custom-designed overlays that provide a powerful set of tools for selection. A critical feature of these pickers is the inclusion of a **local search bar**, which allows users to quickly find a specific folder or tag within a potentially long list, significantly reducing cognitive load. The pickers also support advanced interactions like multi-selection, with clear visual indicators such as **checkmarks** for tags and hierarchical displays with **chevrons** for nested folders. Furthermore, they include persistent **"Clear" and "Done"** actions at the bottom, giving the user explicit control over the filtering process. This level of richness and functionality in a seemingly simple UI element is a hallmark of the Nimbus design and is essential for creating a fluid and efficient filtering experience.
#### 1.2.4. Contextual Outline Panel
For users working with long-form documents, navigation within the page itself is just as important as navigating between pages. The design addresses this with a **contextual outline panel**. This feature is not a permanent fixture of the layout but is instead triggered by a small, round **hamburger button** that appears on the right side of the page content . Clicking this button slides out a docked panel that lists all the headings (H1H6) in the document. This outline serves as an interactive table of contents, allowing users to click on a heading to instantly scroll to that section of the page. This is a prime example of **progressive disclosure**, where a powerful feature is made available on demand without permanently occupying screen real estate. The implementation must ensure this panel is synchronized with the document's content and provides a smooth, responsive scrolling experience.
#### 1.2.5. Single, Consistent Creation Action
To create a predictable and learnable interface, the design mandates a **single, consistent action for creating new content**. This action is embodied by the **"+ Page"** button, which is prominently displayed in the top bar. Regardless of where the user is in the application, this button always performs the same function: it creates a new page within the current context (i.e., the currently selected workspace and folder). This consistency eliminates ambiguity and reduces the cognitive load associated with creating new content. The user does not need to hunt for different "New" buttons in different parts of the interface; they know that the turquoise **"+ Page"** button is always their starting point for creation. This principle of a single, primary call-to-action is a cornerstone of intuitive UI design.
#### 1.2.6. Strictly Separated Workspaces
Reinforcing the **workspace-first** philosophy, this principle dictates that **workspaces must be strictly separated**. The UI must make it impossible for a user to accidentally interact with content from one workspace while believing they are in another. The workspace switcher, located in the sidebar footer and avatar menu, must be a deliberate and clear action . The visual design should also reflect this separation, perhaps by subtly changing the accent color or other visual elements when a different workspace is active. This strict separation is crucial for maintaining data integrity and user trust, especially in a multi-user or multi-project environment. It ensures that the isolated universe of each workspace remains truly isolated.
#### 1.2.7. Bi-Axial Folder/Tag System
This principle is the practical application of the **bi-axial organization** philosophy. The UI must provide clear, distinct, and equally powerful interfaces for managing both **folders** and **tags**. The left sidebar should present these two organizational systems as separate, top-level categories, allowing users to switch between a hierarchical view (folders) and a flat, categorical view (tags). The filtering system in the central panel must also respect this duality, with separate chips for filtering by folder and by tag. The design must avoid conflating the two systems and instead celebrate their complementary nature, giving users the flexibility to organize their information in the way that best suits their mental model and workflow .
#### 1.2.8. Omnipresent Share/Portal Actions
Finally, the design must treat the act of sharing and publishing as a natural extension of the writing process. The commands for **"Share"** and **"Add to portal"** should be **omnipresent** within the editor interface, ensuring that the user can move from creation to dissemination without friction . This creates a **continuum** between writing and publishing. The UI should make it clear what each action does—"Share" for direct link-based sharing, and "Add to portal" for publishing to a branded external space. By keeping these actions always visible, the design encourages a workflow where content is not just created and stored but is actively shared and collaborated upon, fulfilling the promise of "one content, multiple facades."
## 2. Responsive Design Strategy
The successful implementation of the Nimbus-like interface for ObsiViewer hinges on a robust and well-defined responsive design strategy. The application must provide an optimal user experience across a wide spectrum of devices, from large desktop monitors to small mobile phones. This requires a deliberate approach to layout, navigation, and component behavior that adapts intelligently to different screen sizes and input methods. The strategy outlined here employs a mobile-first methodology, a set of clearly defined breakpoints using Tailwind CSS, and distinct layout patterns for desktop, tablet, and mobile viewports. The goal is to ensure that the core functionality and user experience are not just preserved but are enhanced and tailored for each device category.
### 2.1. Breakpoints and Approach
The foundation of the responsive strategy is a combination of a mobile-first development philosophy and a granular set of breakpoints. This approach ensures that the application is built from the ground up with the constraints and capabilities of mobile devices in mind, and then progressively enhanced for larger screens. This is a departure from the traditional desktop-first approach, which often leads to mobile experiences that feel like a compromised afterthought. By starting with the most restrictive environment, the design is forced to prioritize essential content and functionality, resulting in a cleaner, more focused, and more performant application across all platforms.
#### 2.1.1. Tailwind Breakpoints (xs, sm, md, lg, xl, 2xl)
To manage the responsive behavior of the application, a set of standard Tailwind CSS breakpoints will be used. These breakpoints provide a consistent and predictable way to apply different styles and layouts at various screen widths. The chosen breakpoints are designed to cover a wide range of modern devices, from the smallest smartphones to large desktop monitors. The breakpoints are defined as follows:
| Breakpoint | Screen Width | Typical Device Category |
| :--- | :--- | :--- |
| `xs` | `320px` | Small phones (e.g., iPhone SE) |
| `sm` | `640px` | Large phones, small tablets |
| `md` | `768px` | Tablets (e.g., iPad) |
| `lg` | `1024px` | Small laptops, desktop |
| `xl` | `1280px` | Standard desktop |
| `2xl` | `1536px` | Large desktop, wide screens |
These breakpoints will be used in conjunction with Tailwind's responsive prefixes (e.g., `md:flex`, `lg:hidden`) to create adaptive layouts and components. For example, a three-column layout might be applied at the `lg` breakpoint and above, while a single-column layout with a bottom navigation bar would be used for screens smaller than `lg`. This granular control allows for a highly optimized experience at every screen size.
#### 2.1.2. Mobile-First Development Approach
The project will adhere to a **mobile-first** development methodology. This means that the initial development and styling will target the smallest screen sizes (e.g., the `xs` and `sm` breakpoints). The base CSS will be written for the mobile layout, and then media queries will be used to add styles and modify the layout for progressively larger screens (`md`, `lg`, `xl`, etc.). This approach has several key advantages. First, it ensures that the mobile experience is a first-class citizen, not an afterthought. Second, it often leads to cleaner and more maintainable CSS, as the default styles are simple and focused, with complexity added only as needed for larger screens. Third, it can improve performance on mobile devices, as they will download and parse less CSS, avoiding the need to override complex desktop-first styles. This disciplined approach is crucial for delivering a truly responsive and user-friendly application.
### 2.2. Desktop Layout (≥1024px)
For desktop and large tablet devices in landscape mode (screen widths of 1024px and above), the application will display a **three-column layout**. This layout is designed to maximize productivity and information density by keeping all primary navigational and contextual elements visible on screen at all times. It provides a stable and powerful workspace for users who are creating, organizing, and consuming large amounts of information. The layout is reminiscent of classic email clients and file managers, providing a familiar and efficient paradigm for power users.
#### 2.2.1. Three-Column Structure
The desktop layout is composed of three distinct and persistent columns:
1. **Left Sidebar (Navigation):** This column, with a default width of 240-440px, contains the primary navigation elements, including Quick Links, the hierarchical folder tree, and the flat list of tags. It provides the main structural overview of the workspace.
2. **Center Column (Index/Results):** This is the main content area, which displays the list of pages based on the current folder, tag, or search query. It is a scrollable list of page items, each showing a title, snippet, and metadata.
3. **Right Panel (Reader/Editor):** This column displays the content of the currently selected page. It includes the page title, the rich text editor, and the document's action toolbar (e.g., Share, Add to Portal).
This three-column structure allows users to navigate through their content in the left sidebar, scan a list of relevant pages in the center, and read or edit a specific page on the right, all without having to switch views or lose context. This parallel workflow is highly efficient and is a core tenet of the desktop experience.
#### 2.2.2. Resizable Sidebar
To enhance user control and customization, the **left sidebar will be resizable**. Users will be able to click and drag a handle on the right edge of the sidebar to adjust its width within a predefined range (e.g., 240px to 440px). This allows users to tailor the interface to their specific needs and screen size. For example, a user with a very large monitor might want to expand the sidebar to see more of their folder hierarchy, while a user on a smaller laptop might prefer to keep it narrow to maximize the space for the content editor. The resizable functionality will be implemented using a dedicated `resizable-handle` component, which will manage the drag interactions and update the layout dynamically. The user's preferred sidebar width will be persisted in local storage, ensuring a consistent experience across sessions.
#### 2.2.3. Fixed Right Panel for ToC
The **Table of Contents (ToC)** for the currently open document will be displayed in a **fixed right panel** on desktop screens. This panel will be docked to the right edge of the viewport, providing a persistent and easily accessible outline of the document's structure. As the user scrolls through the document, the ToC will remain visible, allowing them to quickly jump between sections by clicking on the corresponding headings. This fixed positioning is a key feature for users working with long and complex documents, as it provides constant orientation and facilitates rapid navigation within the page. The ToC panel will be implemented as a separate component that can be shown or hidden based on the presence of headings in the document and user preference. This design choice reinforces the desktop paradigm of providing multiple, persistent views to support complex workflows.
### 2.3. Tablet Layout (768px ≤ width < 1024px)
For tablet devices and smaller desktop windows (screen widths between 768px and 1023px), the three-column desktop layout is no longer practical due to space constraints. To adapt to this intermediate screen size, the application will switch to a **tab-based navigation system**. This approach maintains access to all the core features of the application but organizes them into a series of full-screen panels that the user can switch between. This ensures that each view has enough space to be usable and readable, while the tab-based navigation provides a clear and intuitive way to move between different parts of the application.
#### 2.3.1. Tab-Based Navigation
Instead of displaying all three columns simultaneously, the tablet layout will use a system of tabs to switch between the main functional areas of the application. The primary tabs will be:
* **Sidebar:** This tab will display the full-width navigation panel, including folders and tags.
* **List:** This tab will show the central index or search results list.
* **Page:** This tab will display the full-width content reader/editor.
* **ToC:** This tab will show the document's Table of Contents.
This tabbed interface allows the application to dedicate the entire screen to one task at a time, which is more appropriate for the smaller screen real estate of a tablet. The user can tap on a tab to instantly switch to that view, providing a fast and fluid navigation experience.
#### 2.3.2. Bottom Navigation Bar
To provide easy access to the primary tabs, a **fixed bottom navigation bar** will be displayed at all times. This bar will contain icons for the main tabs (e.g., Sidebar, List, Page, ToC), allowing the user to switch views with a single tap. The bottom navigation pattern is a standard and highly usable convention on mobile and tablet devices, as it places the primary navigation within easy reach of the user's thumbs. The active tab will be visually highlighted to provide clear feedback on the current view. This persistent navigation bar ensures that the user is never more than one tap away from the main sections of the application.
#### 2.3.3. Drawer for Sidebar
When the user is on the **List** or **Page** tab, the **Sidebar** will be accessible via a **drawer** that slides in from the left side of the screen. This drawer will overlay the current content and can be opened by tapping a menu icon in the top navigation bar. The drawer will contain the full folder and tag navigation, allowing the user to change their context without having to navigate to the dedicated Sidebar tab. This provides a quick and convenient way to switch folders or tags while remaining focused on their current task. The drawer can be dismissed by tapping outside of it or by swiping it away, returning the user to their previous view. This hybrid approach of using both tabs and a drawer provides a flexible and efficient navigation system for the tablet form factor.
### 2.4. Mobile Layout (<768px)
For mobile phones (screen widths below 768px), the design must be further simplified to accommodate the smallest screens and touch-based interactions. The application will adopt a **full-screen, single-tasking model**, where each functional area occupies the entire viewport. Navigation will be handled primarily through a **bottom navigation bar** with four distinct tabs, providing a clear and thumb-friendly way to switch between the main features of the app. The goal is to provide a focused and uncluttered experience that is optimized for on-the-go use.
#### 2.4.1. Bottom Navigation with 4 Tabs
The primary navigation on mobile will be a **bottom navigation bar with four tabs**. These tabs will provide direct access to the core functions of the application:
1. **☰ (Menu):** This tab will open the sidebar drawer, providing access to folders and tags.
2. **🔍 (Search):** This tab will focus on the search bar and display search results.
3. **📄 (Page):** This tab will display the content of the currently selected page.
4. **📋 (ToC):** This tab will show the Table of Contents for the current page.
This four-tab layout provides a clear and logical grouping of features, ensuring that the most common tasks are always just one tap away. The use of standard icons makes the navigation immediately understandable to users familiar with mobile app conventions.
#### 2.4.2. Full-Width Content Panels
In the mobile layout, each of the main content areas will occupy the **full width of the screen**. This provides maximum readability and touch-target size for each element. The **sidebar** will be presented as a **drawer** that slides in from the left, covering most of the screen. The **search results list** will be a vertically scrollable list of full-width items. The **page viewer** will also be full-width, with the content optimized for mobile reading (e.g., appropriate font sizes, line heights, and image scaling). This single-tasking approach prevents the interface from feeling cramped and ensures that the user's attention is focused on one thing at a time.
#### 2.4.3. Inline/Collapsible ToC
On mobile, the **Table of Contents (ToC)** will not be a persistent panel due to space constraints. Instead, it will be implemented as an **inline, collapsible section** within the page content itself. A button, likely fixed to the bottom-right of the screen, will allow the user to toggle the visibility of the ToC. When opened, the ToC will appear as a list of links within the page, pushing the content down. Alternatively, it could be implemented as a modal or a bottom sheet that slides up from the bottom of the screen. This approach makes the ToC accessible on mobile without sacrificing valuable screen real estate, providing a practical solution for navigating long documents on a small screen.
## 3. Feature Flag and UI Toggle Implementation
To ensure a smooth transition and allow for user choice, the new Nimbus-like UI will be introduced behind a **feature flag**. This allows the legacy interface to remain fully functional while the new design is being developed and tested. A prominent toggle in the application's navbar will allow users to switch between the two UIs at any time, with their preference being persisted across sessions. This architecture is critical for managing risk, gathering user feedback, and ensuring a zero-regression deployment.
### 3.1. UI Mode Service
The core of the feature flag system is a dedicated Angular service, `UiModeService`, which will manage the application's UI state. This service will use Angular's new `signal` API for fine-grained reactivity, ensuring that components update instantly when the UI mode changes. It will also handle the persistence of the user's choice using the browser's `localStorage`.
#### 3.1.1. Signal-Based State Management
The `UiModeService` will utilize an Angular `signal` to hold the current UI mode. Signals are a new primitive in Angular that provide a simpler and more performant way to manage state compared to traditional RxJS observables for simple boolean flags. When the `toggleUIMode()` method is called, it will update the signal's value, which will automatically trigger re-rendering in any component that depends on it. This approach minimizes unnecessary change detection cycles and leads to a more responsive user interface.
#### 3.1.2. localStorage Persistence
To provide a seamless user experience, the selected UI mode must be remembered between sessions. The `UiModeService` will achieve this by saving the user's choice to `localStorage` whenever the mode is toggled. When the application is first loaded, the service will check `localStorage` for a saved preference. If one exists, it will initialize the signal with that value; otherwise, it will default to the new Nimbus mode. This ensures that users only have to make the choice once, and their preference will be respected every time they use the application.
### 3.2. Adaptive Layout Wrapper
A new top-level component, `AppShellAdaptiveComponent`, will act as a wrapper or router for the two different layout shells. This component will be responsible for conditionally rendering either the `AppShellNimbusLayoutComponent` (the new UI) or the `AppShellLegacyLayoutComponent` (the old UI) based on the current state of the `UiModeService`.
#### 3.2.1. Conditional Rendering of Layouts
The `AppShellAdaptiveComponent` will use Angular's `@if` block to render the appropriate layout component. It will inject the `UiModeService` and read the `isNimbusMode` signal. The template will be a simple conditional statement that displays one layout or the other. This clean separation ensures that the logic for choosing a UI is contained in a single place and that the two layout components remain decoupled and independent of each other.
#### 3.2.2. Integration with UiModeService
The `AppShellAdaptiveComponent` will be the primary consumer of the `UiModeService`. By injecting the service and reading its signal, it will react to any changes in the UI mode. When a user clicks the toggle button in the navbar, the `UiModeService` updates its signal, which in turn causes the `AppShellAdaptiveComponent` to re-render and switch the entire application layout. This reactive flow is efficient and easy to reason about, forming the backbone of the feature flag implementation.
### 3.3. Navbar Toggle Button
The user-facing control for the feature flag will be a button placed in the main application navbar. This button will be clearly labeled to indicate its function and will provide immediate visual feedback on the current UI mode.
#### 3.3.1. Visual Indication of Current Mode
The toggle button's label will change dynamically to reflect the current state. When the Nimbus UI is active, the button might display "🔧 Legacy" to indicate that clicking it will switch to the legacy UI. Conversely, when the legacy UI is active, the button might show "✨ Nimbus" to indicate the option to switch to the new design. This clear, contextual labeling removes any ambiguity about what the button will do.
#### 3.3.2. State-Switching Logic
The button's `(click)` event will be bound to a method in the navbar component that simply calls `uiModeService.toggleUIMode()`. This method will handle all the logic of flipping the signal and persisting the new state to `localStorage`. The navbar component itself does not need to contain any complex logic; it just acts as a trigger for the service, keeping the component's code clean and focused on its primary responsibility of navigation.
## 4. Component Architecture and Responsiveness
To manage the complexity of a fully responsive application, a clear and scalable component architecture is required. The strategy involves creating distinct component variants for desktop and mobile views, while sharing common logic. This is combined with a dynamic injection mechanism that loads the appropriate variant based on the current screen size, detected using Angular's CDK utilities.
### 4.1. Desktop/Mobile Component Variants
Instead of creating monolithic components with complex, inline responsive logic, the design promotes the creation of separate, specialized components for different screen sizes. This leads to cleaner, more maintainable code and allows each variant to be optimized for its specific context.
#### 4.1.1. Shared Logic Components
For each major feature (e.g., sidebar, search bar, note view), a base component will be created to encapsulate the shared logic and state. This component will not have a template of its own but will instead be responsible for managing data, handling business logic, and determining which of its child variants (desktop or mobile) should be displayed. This separation of concerns ensures that logic is not duplicated between the desktop and mobile versions of a component.
#### 4.1.2. Desktop-Specific Components (Fixed, Resizable)
For the desktop view (≥1024px), components will be designed to take advantage of the larger screen real estate. For example, the `app-left-sidebar.desktop.component.ts` will implement a fixed, resizable panel. These components will use CSS layouts like Flexbox or Grid to create the stable, multi-column structure. Their styling will be optimized for mouse and keyboard interaction, with hover states and precise click targets.
#### 4.1.3. Mobile-Specific Components (Drawer, Inline)
For the mobile view (<1024px), components will be designed for touch interaction and smaller screens. The `app-left-sidebar.mobile.component.ts`, for instance, will implement a drawer that slides in from the side. These components will use full-width layouts and larger touch targets. Animations and transitions will be used to provide feedback and create a fluid, app-like feel. The logic within these components will be tailored to the mobile interaction model, such as handling swipe gestures for dismissal.
### 4.2. Breakpoint Detection and Injection
The mechanism for switching between desktop and mobile variants will be handled by the shared logic component. It will use Angular's CDK to observe screen size changes and dynamically inject the correct variant into the view.
#### 4.2.1. Using Angular CDK BreakpointObserver
The `BreakpointObserver` from `@angular/cdk/layout` is the ideal tool for this task. The shared logic component will inject this service and use it to create an observable stream that emits a boolean value indicating whether the screen width is above or below a certain threshold (e.g., `Breakpoints.Large` for 1024px). This provides a clean, reactive way to respond to changes in viewport size.
#### 4.2.2. Dynamic Component Injection with `ngComponentOutlet`
Based on the boolean value from the `BreakpointObserver`, the shared logic component's template will use Angular's `ngComponentOutlet` directive to dynamically render the appropriate variant. The template will contain an `@if` block that checks the breakpoint state and then uses `*ngComponentOutlet` to inject either the desktop or mobile component. This powerful technique allows for a completely different component tree to be rendered for different screen sizes, providing the ultimate flexibility in responsive design.
## 5. Mobile Navigation and Gestures
The mobile experience is defined by its navigation patterns and touch-based interactions. To create an intuitive and efficient mobile app, the design incorporates a tab-based system, swipe navigation, and other touch-friendly gestures. These elements are managed by dedicated services and directives to keep the logic clean and reusable.
### 5.1. Tab/Drawer Navigation System
On mobile and tablet devices, the primary navigation will be handled by a system of tabs and drawers. This replaces the persistent three-column layout of the desktop with a more space-efficient, single-tasking model.
#### 5.1.1. MobileNavService for State Management
A `MobileNavService` will be created to manage the state of the mobile navigation. This service will use an Angular `signal` to track the currently active tab (e.g., 'sidebar', 'list', 'page', 'toc'). Other components, such as the `BottomNavComponent`, will inject this service to read the current state and to update it when the user interacts with the navigation. This centralized state management ensures that the navigation UI remains consistent and synchronized across the application.
#### 5.1.2. BottomNavComponent Implementation
The `BottomNavComponent` will be a sticky navigation bar fixed to the bottom of the screen on mobile devices. It will display icons for the four primary tabs. The component will read the active tab from the `MobileNavService` to highlight the correct icon. When a user taps an icon, the component will call a method on the service to update the active tab, which will in turn trigger a re-render of the main content area to show the corresponding view.
### 5.2. Swipe Navigation
To enhance the mobile experience and make navigation feel more fluid, horizontal swipe gestures will be supported for switching between tabs.
#### 5.2.1. SwipeNavDirective for Gesture Detection
A custom directive, `SwipeNavDirective`, will be created to encapsulate the logic for detecting swipe gestures. This directive will use `@HostListener` to listen for `touchstart` and `touchend` events on a host element. By comparing the start and end coordinates of the touch, it can determine the direction of the swipe.
#### 5.2.2. Horizontal Swipe for Tab Switching
The `SwipeNavDirective` will be applied to the main content area. When a swipe is detected, it will emit an event (e.g., `swipeLeft` or `swipeRight`). A parent component will listen for these events and use the `MobileNavService` to switch to the next or previous tab in the sequence. This provides a natural and intuitive way for users to navigate the application, mirroring the behavior of many native mobile apps.
### 5.3. Touch-Friendly Interactions
Beyond basic navigation, other touch-friendly interactions will be implemented to improve usability on mobile devices.
#### 5.3.1. Long-Press for Context Menus
A long-press gesture on items in a list (e.g., a page in the search results) will trigger a context menu. This menu will provide quick access to common actions like "Favorite," "Delete," or "Open in New Tab." This is a standard mobile pattern that provides power-user functionality without cluttering the main interface.
#### 5.3.2. Pull-to-Refresh (Optional)
As an optional enhancement, a pull-to-refresh gesture could be implemented on scrollable lists. This would allow users to manually trigger a refresh of the data, which is a common and expected behavior in mobile applications. This would likely be implemented using a third-party library or a custom directive that listens for scroll events and detects the "pull" gesture.
## 6. Mobile-First Component Specifications
To ensure a high-quality mobile experience, each component must be designed and built with a mobile-first mindset. This section provides detailed specifications for key mobile components, including their layout, styling, and behavior.
### 6.1. Bottom Navigation (Mobile)
The bottom navigation bar is the primary means of navigation on mobile and must be robust and user-friendly.
#### 6.1.1. Fixed Positioning and Styling
The `BottomNavComponent` will be fixed to the bottom of the viewport using `position: fixed`. It will have a solid background color to ensure it is always visible and legible, even when scrolling through content. It will use Flexbox to evenly distribute the tab buttons across its width. The styling will be simple and clean, with a top border to visually separate it from the content area.
#### 6.1.2. Active State Indication
The currently active tab must be clearly indicated. This will be achieved by changing the color of the icon and label for the active button. A subtle background color change on the active button could also be used to provide additional visual feedback. This state will be driven by the `activeTab` signal from the `MobileNavService`.
### 6.2. Drawer Sidebar (Mobile)
The sidebar drawer provides access to the main navigation (folders and tags) without leaving the current context.
#### 6.2.1. Animated Slide-In/Out
The drawer will be implemented as a `fixed` position element that is initially translated off-screen. When opened, a CSS transition will be used to animate its `transform` property, causing it to slide in smoothly from the left. The same animation will be used in reverse when the drawer is closed. This provides a clear and fluid visual cue to the user.
#### 6.2.2. Backdrop for Dismissal
When the drawer is open, a semi-transparent backdrop will be displayed over the main content. This backdrop serves two purposes: it visually de-emphasizes the background content, focusing the user's attention on the drawer, and it provides a large tap target to dismiss the drawer. Clicking on the backdrop will trigger the close animation and hide the drawer.
### 6.3. Compact Search Bar (Mobile)
The search bar on mobile needs to be compact yet powerful, providing access to search and filtering without taking up too much vertical space.
#### 6.3.1. Integrated Menu Toggle
The mobile search bar will be a single, integrated component that includes a button to toggle the sidebar drawer. This button will be placed on the left side of the search input field, providing a clear and consistent way to access the main navigation.
#### 6.3.2. Horizontally Scrollable Filter Badges
When filters are active, they will be displayed as small "chips" or badges below the search input. On mobile, where horizontal space is limited, this row of badges will be horizontally scrollable. This allows the user to see all active filters without the row wrapping and taking up too much vertical space. Each badge will also have a small "x" icon to allow for quick removal of individual filters.
### 6.4. Optimized Result List Item (Mobile)
Each item in the search results list must be designed for clarity and easy interaction on a small screen.
#### 6.4.1. Stacked Layout for Title, Date, and Tags
On mobile, the layout for each list item will be a stacked, vertical layout. The page title will be at the top, followed by a line containing the last modified date, and then a row of tags. This vertical stacking ensures that each piece of information is readable without horizontal scrolling.
#### 6.4.2. Truncated Excerpt with `line-clamp`
A short excerpt of the page's content will be displayed below the metadata. To prevent this excerpt from taking up too much space, its height will be limited using the CSS `line-clamp` property. This will truncate the text after a specified number of lines (e.g., 2 or 3) and add an ellipsis to indicate that the text has been cut off.
### 6.5. Responsive Markdown Viewer
The markdown content viewer must be responsive and provide a comfortable reading experience on any screen size.
#### 6.5.1. Mobile-First Prose Styling
The styling for the rendered markdown will be mobile-first. Base font sizes, line heights, and margins will be optimized for small screens. Tailwind's `prose` plugin will be used, with responsive variants like `prose-sm` for mobile and `prose-base` for larger screens, to ensure that the typography is always readable and well-proportioned.
#### 6.5.2. Inline ToC Toggle Button
As specified in the responsive strategy, the Table of Contents on mobile will not be a persistent panel. Instead, a floating action button (FAB) will be displayed in the bottom-right corner of the screen when the document has headings. Tapping this button will toggle the visibility of an inline ToC that appears within the document flow.
### 6.6. Adaptive ToC Drawer
The ToC component itself must adapt its behavior and appearance based on the screen size.
#### 6.6.1. Desktop: Fixed Right Panel
On desktop (≥1024px), the `app-toc-drawer` component will render a fixed panel on the right side of the screen. This panel will be styled with a distinct background color and a left border to separate it from the main content. It will be vertically scrollable if the list of headings is long.
#### 6.6.2. Mobile: Collapsible Inline Section with Animation
On mobile (<1024px), the same `app-toc-drawer` component will render a collapsible section that is inserted into the main content flow. The component will use an Angular animation trigger to smoothly animate the opening and closing of this section, animating its height from 0 to its full size. This provides a fluid and polished user experience.
## 7. Performance and Mobile Optimizations
A great user experience on mobile is heavily dependent on performance. The application must be fast to load, smooth to scroll, and responsive to user input. This section outlines key performance optimizations that will be implemented, with a focus on achieving high scores in tools like Google Lighthouse.
### 7.1. Critical Rendering Optimizations
Several techniques will be used to optimize the critical rendering path and improve perceived performance.
#### 7.1.1. Lazy-Loading Images
All images, including those in markdown content and bookmark cards, will be lazy-loaded. This is achieved by adding the `loading="lazy"` attribute to `<img>` tags. This tells the browser to defer loading the image until it is about to enter the viewport, significantly reducing the initial page load time and data usage.
#### 7.1.2. Virtual Scrolling for Long Lists
For lists that can contain a large number of items (e.g., the search results list), a virtual scrolling technique will be used. The Angular CDK's `VirtualScrollViewport` is an excellent tool for this. It works by only rendering the items that are currently visible in the viewport, plus a small buffer. As the user scrolls, it dynamically recycles and re-renders the items, keeping the DOM size small and ensuring smooth 60fps scrolling even with thousands of items.
#### 7.1.3. Debounced Search Input
To avoid firing a search request on every single keystroke, the search input field will be debounced. This means that the search function will only be executed after the user has stopped typing for a short period (e.g., 300ms on mobile, 150ms on desktop). This reduces the number of API calls and prevents the UI from becoming sluggish due to rapid, unnecessary re-rendering of search results.
### 7.2. Lighthouse Mobile Targets
Google Lighthouse provides a comprehensive audit of a web application's performance, accessibility, and best practices. The goal is to achieve high scores across the board, with a particular focus on the mobile audit.
#### 7.2.1. Performance Score ≥ 85
A performance score of 85 or higher on the mobile audit is the target. This will be achieved by implementing the optimizations listed above, as well as other best practices like minifying code, compressing assets, and using a content delivery network (CDN). The performance budget will be monitored throughout the development process.
#### 7.2.2. Accessibility Score ≥ 95
An accessibility score of 95 or higher is the target. This will be achieved by following the WCAG 2.1 AA guidelines, as detailed in the next section. This includes ensuring sufficient color contrast, providing alternative text for images, and making the application fully navigable with a keyboard.
#### 7.2.3. Best Practices Score ≥ 90
A best practices score of 90 or higher is the target. This audit checks for common web development pitfalls, such as using deprecated APIs, having security vulnerabilities, or not using HTTPS. Adhering to modern web standards and security best practices will ensure a high score in this category.
## 8. Accessibility and Usability
An accessible application is a usable application. The redesign will prioritize accessibility from the start, ensuring that the ObsiViewer is usable by as many people as possible, regardless of their abilities or the devices they use.
### 8.1. WCAG 2.1 AA Compliance
The Web Content Accessibility Guidelines (WCAG) 2.1 provide a comprehensive set of recommendations for making web content more accessible. The goal is to meet the **AA** level of conformance.
#### 8.1.1. Sufficient Color Contrast
All text and interactive elements must have a color contrast ratio of at least **4.5:1** against their background. For large text (18pt or 14pt bold), the ratio can be 3:1. This ensures that text is readable for users with low vision or color blindness. Tools will be used during development to check contrast ratios for all color combinations in both light and dark themes.
#### 8.1.2. Visible Focus Indicators
All interactive elements (links, buttons, form inputs) must have a visible focus indicator when they are navigated to using the keyboard (e.g., with the Tab key). This is typically a visible outline or border. This is crucial for keyboard-only users to know which element currently has focus.
#### 8.1.3. Zoom Compatibility (≤200%)
The application must remain fully functional and usable when the browser's zoom level is increased up to **200%**. This means that the layout should reflow appropriately, and horizontal scrolling should be avoided. This is a key requirement for users with low vision who rely on browser zoom to read content.
### 8.2. Keyboard Navigation
The application must be fully navigable and operable using only a keyboard.
#### 8.2.1. Complete Tab Navigation
All interactive elements must be reachable and operable using the Tab key to move forward and Shift+Tab to move backward through the interface. The tab order must be logical and follow the visual flow of the page.
#### 8.2.2. Keyboard Shortcuts for Common Actions
To improve efficiency for power users, keyboard shortcuts will be provided for common actions. For example, `Ctrl/Cmd + K` could open a command palette, and `Ctrl/Cmd + F` could focus the search bar. These shortcuts will be documented and discoverable.
### 8.3. Touch Accessibility
On mobile devices, touch targets must be large enough and well-spaced to be easily and accurately tapped.
#### 8.3.1. Minimum Touch Target Size (44x44px)
All interactive elements, such as buttons and links, should have a touch target size of at least **44x44 pixels**. This is the recommended minimum size by both Apple and Google to ensure that elements can be easily tapped without accidentally hitting adjacent targets.
#### 8.3.2. Descriptive ARIA Labels
For elements that are not clearly labeled with text (e.g., icon buttons), a descriptive `aria-label` attribute must be provided. This label is read by screen readers, providing context to users who cannot see the visual icon. This is essential for making the application's functionality understandable to users with visual impairments.
## 9. Implementation Plan and Deliverables
The project will be executed in a series of phases, with clear deliverables for each stage. This structured approach ensures that the project stays on track and that progress can be measured and reviewed.
### 9.1. Phased Implementation Schedule
The implementation will be broken down into three main phases, with an estimated timeline of 13-21 days for a single frontend engineer.
#### 9.1.1. Phase 1: Feature Flag and Responsive Shell (3-5 days)
This initial phase focuses on building the foundational architecture. It includes implementing the `UiModeService`, the `AppShellAdaptiveComponent`, and the navbar toggle button. It also involves setting up the Tailwind breakpoints and creating the basic three-column responsive shell for the desktop layout.
#### 9.1.2. Phase 2: Mobile Navigation and Components (7-10 days)
This phase is dedicated to building out the mobile experience. It includes creating the `MobileNavService`, the `BottomNavComponent`, and the swipe navigation directive. It also involves developing the mobile-specific variants of key components like the sidebar drawer, the compact search bar, and the optimized result list items.
#### 9.1.3. Phase 3: Gestures, Accessibility, and Testing (3-6 days)
The final phase focuses on polishing the user experience and ensuring quality. It includes implementing advanced gestures like long-press menus, conducting a full accessibility audit to meet WCAG 2.1 AA standards, and writing end-to-end and visual regression tests. It also includes creating the required documentation.
### 9.2. Code Deliverables
The primary output of the project will be the source code for the new features and components.
#### 9.2.1. UI Mode Service and Toggle
This includes the `UiModeService` for state management, the `AppShellAdaptiveComponent` for layout switching, and the toggle button integrated into the navbar.
#### 9.2.2. Responsive Component Wrappers
This includes the shared logic components for the sidebar, search bar, and note view, which are responsible for dynamically injecting their desktop or mobile variants.
#### 9.2.3. Mobile-Specific Components and Directives
This includes all the mobile-first components, such as the `BottomNavComponent`, the drawer sidebar, the compact search bar, and the `SwipeNavDirective`.
### 9.3. Documentation and Testing
High-quality documentation and a comprehensive test suite are essential for the long-term maintainability and success of the project.
#### 9.3.1. README_UI.md, MOBILE_GUIDE.md, RESPONSIVE_CHECKLIST.md
Three key documentation files will be created:
* `README_UI.md`: An overview of the new UI architecture, including screenshots of the three main breakpoints.
* `MOBILE_GUIDE.md`: A detailed guide to the mobile navigation patterns, gestures, and component behaviors.
* `RESPONSIVE_CHECKLIST.md`: A checklist for testing the application's responsiveness and functionality across different devices and screen sizes.
#### 9.3.2. E2E and Visual Regression Tests
End-to-end tests will be written to cover critical user flows, such as toggling the UI, navigating on mobile, and performing searches. Visual regression tests will be implemented to automatically detect any unintended changes to the UI's appearance across the desktop, tablet, and mobile layouts.
#### 9.3.3. Accessibility Audit Checklist
A final checklist will be created to document the results of the accessibility audit, confirming that all WCAG 2.1 AA criteria have been met. This will serve as a record of compliance and a guide for future development.

View File

@ -0,0 +1,760 @@
# 🎯 Prompt Windsurf — ObsiViewer Nimbus UI (Desktop + Mobile)
## ObsiViewer → UI/UX "Nimbus-like" (simple, dense, rapide)
**Rôle & mode :** Agis comme **Staff Frontend Engineer Angular 20 + UX designer**. Raisonnement détaillé autorisé. Tu as les pleins pouvoirs de refactor UI, d'ajout de composants, et de migration CSS vers Tailwind. Conserve la compatibilité de toutes features existantes.
**Contrainte majeure :** L'interface doit être **100% responsive** (Desktop + Mobile). Un **bouton toggle** dans la navbar permet de basculer entre l'ancienne interface et la nouvelle sans perte d'état.
---
## Contexte rapide
* Projet : **ObsiViewer** (Angular 20 + Tailwind, Node/Express backend).
* Objectif : Refondre l'interface selon un design **Nimbus Notes**-like.
* Cœurs d'usage : navigation par **dossiers**, **tags**, **recherche**, **lecture markdown** plein écran, **ToC** à droite, **tri et filtres** rapides.
* **Nouveauté** : Design adaptatif complet (Desktop/Mobile/Tablet) avec UI toggle persisté.
---
## 🎯 Objectif final (résumé)
### Desktop (≥1024px)
Refondre l'interface ObsiViewer en **3 colonnes** :
1. **Sidebar gauche** (Quick Links, Dossiers arborescents, Tags) — Redimensionnable.
2. **Colonne centrale** Liste des pages (recherche, filtres dossiers/tags, tris, résultats virtualisés).
3. **Vue de page** à droite (lecture markdown, barre d'actions, **panneau sommaire/ToC** docké à l'extrême droite).
Le tout **compact, performant, thème clair/sombre**, navigation au clavier, états persistés localement.
### Mobile/Tablet (<1024px)
Une navigation **par onglets/drawer** intelligente :
- **Tab 1 : Sidebar** (dossiers, tags, recherche) — Panneau full-width ou drawer collapsible.
- **Tab 2 : Liste** (résultats de recherche) — Full-width scrollable.
- **Tab 3 : Page** (markdown) — Full-width avec ToC inline collapsible ou drawer.
**Gestures** : Swipe horizontal pour navigation onglets, pull-to-refresh, tap = open item.
---
## 📋 Architecture Feature Flag & Toggle
### 1) Toggle UI dans la NavBar
Ajouter un **bouton toggle** dans `src/app/layout/app-navbar/app-navbar.component.ts` :
```html
<!-- app-navbar.component.html (snippet) -->
<div class="flex items-center gap-2">
<!-- Autres boutons -->
<button
(click)="toggleUIMode()"
[attr.aria-label]="'Toggle ' + (isNimbusMode$ | async ? 'legacy' : 'nimbus') + ' UI'"
class="p-2 rounded hover:bg-gray-100 dark:hover:bg-gray-800">
<span *ngIf="(isNimbusMode$ | async)">✨ Nimbus</span>
<span *ngIf="!(isNimbusMode$ | async)">🔧 Legacy</span>
</button>
</div>
```
### 2) Service de gestion du mode UI
Créer `src/app/shared/services/ui-mode.service.ts` :
```typescript
import { Injectable, signal } from '@angular/core';
@Injectable({ providedIn: 'root' })
export class UiModeService {
// Signal pour réactivité fine-grained
isNimbusMode = signal<boolean>(this.loadUIMode());
constructor() {}
toggleUIMode() {
const newMode = !this.isNimbusMode();
this.isNimbusMode.set(newMode);
localStorage.setItem('obsiviewer-ui-mode', newMode ? 'nimbus' : 'legacy');
}
private loadUIMode(): boolean {
if (typeof localStorage === 'undefined') return false;
const saved = localStorage.getItem('obsiviewer-ui-mode');
return saved ? saved === 'nimbus' : true; // Nimbus par défaut
}
}
```
### 3) Layout wrapper avec feature flag
Créer `src/app/layout/app-shell-adaptive/app-shell-adaptive.component.ts` :
```typescript
import { Component, inject } from '@angular/core';
import { UiModeService } from '@app/shared/services/ui-mode.service';
import { AppShellNimbusLayoutComponent } from '../app-shell-nimbus/app-shell-nimbus.component';
import { AppShellLegacyLayoutComponent } from '../app-shell-legacy/app-shell-legacy.component';
@Component({
selector: 'app-shell-adaptive',
template: `
@if (uiMode.isNimbusMode()) {
<app-shell-nimbus-layout></app-shell-nimbus-layout>
} @else {
<app-shell-legacy-layout></app-shell-legacy-layout>
}
`,
standalone: true,
imports: [AppShellNimbusLayoutComponent, AppShellLegacyLayoutComponent],
})
export class AppShellAdaptiveComponent {
uiMode = inject(UiModeService);
}
```
---
## 🎨 Responsive Design Strategy
### Breakpoints Tailwind (standard)
```typescript
// tailwind.config.js
module.exports = {
theme: {
screens: {
'xs': '320px', // iPhone SE
'sm': '640px', // Petites tablettes
'md': '768px', // iPad, tablettes
'lg': '1024px', // Desktop compact
'xl': '1280px', // Desktop standard
'2xl': '1536px', // Larges écrans
},
},
};
```
### Mobile First Approach
**Développer pour mobile d'abord, puis enrichir pour desktop.**
---
## 📱 Layouts Responsifs
### Desktop Layout (≥1024px)
```
┌─────────────────────────────────────────────────────────┐
│ NAVBAR (Dark, fixed, h-14) │
├────────────────┬──────────────────┬──────────────────────┤
│ │ │ │
│ SIDEBAR │ RESULT LIST │ NOTE VIEW + TOC │
│ (240-440px) │ (virtualized) │ (Resizable) │
│ Resizable │ │ │
│ │ │ │
│ - Quick │ - Search bar │ - Markdown │
│ Links │ - Filters │ - ToC drawer │
│ - Folders │ - Items (80px) │ - Actions bar │
│ - Tags │ - Pagination │ │
│ │ │ │
└────────────────┴──────────────────┴──────────────────────┘
```
### Tablet Layout (768px ≤ width < 1024px)
```
┌──────────────────────────────────────┐
│ NAVBAR + Toggle (fixed, h-14) │
├──────────────────────────────────────┤
│ TAB NAVIGATION (fixed, bottom) │
│ [Sidebar] [List] [Page] [ToC] │
├──────────────────────────────────────┤
│ │
│ ACTIVE TAB CONTENT (scrollable) │
│ - Drawer si besoin │
│ - Full-width panels │
│ │
└──────────────────────────────────────┘
```
### Mobile Layout (<768px)
```
┌──────────────────────────────────┐
│ NAVBAR (compact, h-12) │
│ [Menu] [Search] [Toggle] │
├──────────────────────────────────┤
│ │
│ TAB/DRAWER NAVIGATION │
│ [≡] [🔍] [📄] [📋] │
│ │
│ CONTENT AREA (Full-width) │
│ - Drawer sidebar (80vw left) │
│ - Swipeable list (list tab) │
│ - Markdown full-screen (page) │
│ - Inline ToC (toggle button) │
│ │
├──────────────────────────────────┤
│ Bottom Navigation (sticky) │
│ Tab buttons (4 icônes) │
└──────────────────────────────────┘
```
---
## 🎬 Composants Nimbus Responsifs
### Desktop/Mobile Variants
Chaque composant doit avoir des **variants responsifs** :
```
app-left-sidebar/
├── app-left-sidebar.component.ts # Logique partagée
├── app-left-sidebar.desktop.component.ts # ≥1024px (fixed, resizable)
└── app-left-sidebar.mobile.component.ts # <1024px (drawer)
app-center-list/
├── app-center-list.component.ts
├── app-center-list.desktop.component.ts # ≥1024px (2 colonnes)
└── app-center-list.mobile.component.ts # <1024px (full-width)
app-note-view/
├── app-note-view.component.ts
├── app-note-view.desktop.component.ts # ≥1024px (3 colonnes + ToC)
└── app-note-view.mobile.component.ts # <1024px (full-width + ToC inline)
app-toc-drawer/
├── app-toc-drawer.component.ts
├── app-toc-drawer.desktop.component.ts # ≥1024px (Fixed right)
└── app-toc-drawer.mobile.component.ts # <1024px (Collapsible, inline)
```
### Détection et Injection
```typescript
// app-left-sidebar.component.ts
import { Component, inject } from '@angular/core';
import { BreakpointObserver, Breakpoints } from '@angular/cdk/layout';
@Component({
selector: 'app-left-sidebar',
standalone: true,
template: `
@if (isDesktop$ | async) {
<ng-container *ngComponentOutlet="DesktopSidebarComponent"></ng-container>
} @else {
<ng-container *ngComponentOutlet="MobileSidebarDrawerComponent"></ng-container>
}
`,
})
export class AppLeftSidebarComponent {
private breakpoint = inject(BreakpointObserver);
isDesktop$ = this.breakpoint.observe(Breakpoints.Large).pipe(
map(result => result.matches)
);
}
```
---
## 📱 Navigation Mobile Avancée
### Tab/Drawer Navigation
```typescript
// src/shared/services/mobile-nav.service.ts
@Injectable({ providedIn: 'root' })
export class MobileNavService {
activeTab = signal<'sidebar' | 'list' | 'page' | 'toc'>('list');
setTab(tab: 'sidebar' | 'list' | 'page' | 'toc') {
this.activeTab.set(tab);
// Persist if needed
}
}
// Usage in component
<app-bottom-nav [activeTab]="mobileNav.activeTab()"
(tabChange)="mobileNav.setTab($event)">
</app-bottom-nav>
```
### Swipe Navigation (Gestures)
```typescript
// Directive pour détection de swipe
import { Directive, Output, EventEmitter, HostListener } from '@angular/core';
@Directive({
selector: '[appSwipeNav]',
standalone: true,
})
export class SwipeNavDirective {
@Output() swipeLeft = new EventEmitter<void>();
@Output() swipeRight = new EventEmitter<void>();
private startX = 0;
@HostListener('touchstart', ['$event'])
onTouchStart(e: TouchEvent) {
this.startX = e.touches[0].clientX;
}
@HostListener('touchend', ['$event'])
onTouchEnd(e: TouchEvent) {
const endX = e.changedTouches[0].clientX;
const diff = this.startX - endX;
if (Math.abs(diff) > 50) { // Seuil minimum
if (diff > 0) this.swipeLeft.emit();
else this.swipeRight.emit();
}
}
}
```
---
## 🎨 Composants Spécifiques (Mobile-First)
### 1) Bottom Navigation (Mobile)
```html
<!-- app-bottom-nav.component.html -->
<nav class="fixed bottom-0 left-0 right-0 bg-white dark:bg-gray-900 border-t
border-gray-200 dark:border-gray-800 h-16 flex justify-around md:hidden">
<button *ngFor="let tab of tabs"
(click)="selectTab(tab.id)"
[class.active]="activeTab === tab.id"
class="flex-1 flex flex-col items-center justify-center gap-1
text-xs hover:bg-gray-50 dark:hover:bg-gray-800">
<span class="text-lg">{{ tab.icon }}</span>
<span>{{ tab.label }}</span>
</button>
</nav>
```
### 2) Drawer Sidebar (Mobile)
```html
<!-- app-left-sidebar.mobile.component.html -->
<aside class="fixed left-0 top-0 bottom-0 w-80vw max-w-xs
bg-white dark:bg-gray-900 shadow-lg z-50
transform transition-transform duration-300"
[class.-translate-x-full]="!isOpen">
<!-- Contenu sidebar -->
<button (click)="close()" class="absolute top-4 right-4"></button>
</aside>
<!-- Backdrop -->
<div *ngIf="isOpen"
(click)="close()"
class="fixed inset-0 bg-black/50 z-40 md:hidden"></div>
```
### 3) Search Bar Compact (Mobile)
```html
<!-- app-search-bar.mobile.component.html -->
<div class="sticky top-0 bg-white dark:bg-gray-900 p-2 shadow-sm z-10">
<div class="flex gap-2">
<!-- Menu toggle -->
<button (click)="toggleSidebar()"
class="p-2 rounded hover:bg-gray-100">☰</button>
<!-- Search input (full-width on mobile) -->
<input type="text"
placeholder="Search..."
class="flex-1 px-3 py-2 rounded border dark:border-gray-700">
<!-- Filters button (mobile: popover instead of dropdown) -->
<button (click)="openFilters()"
class="p-2 rounded hover:bg-gray-100">⚙️</button>
</div>
<!-- Active badges (scrollable horizontally) -->
<div class="flex gap-1 mt-2 overflow-x-auto">
<span *ngFor="let badge of activeBadges"
class="badge badge-sm">
{{ badge }} ✕
</span>
</div>
</div>
```
### 4) Result List Item (Mobile-Optimized)
```html
<!-- app-result-list-item.component.html -->
<div class="p-3 border-b hover:bg-gray-50 dark:hover:bg-gray-800 cursor-pointer">
<!-- Title -->
<h3 class="font-semibold text-sm sm:text-base truncate">
{{ item.title }}
</h3>
<!-- Date + Tags (stacked on mobile) -->
<div class="flex flex-col sm:flex-row sm:items-center gap-1 mt-1 text-xs text-gray-600">
<span>{{ item.modified | date:'short' }}</span>
<div class="flex gap-1 flex-wrap">
<span *ngFor="let tag of item.tags"
class="badge badge-sm">{{ tag }}</span>
</div>
</div>
<!-- Excerpt (truncated) -->
<p class="mt-2 text-xs text-gray-600 line-clamp-2">
{{ item.excerpt }}
</p>
</div>
```
### 5) Markdown Viewer (Mobile-Responsive)
```html
<!-- app-markdown-viewer.component.html -->
<article class="prose dark:prose-invert max-w-none
prose-sm sm:prose-base
prose-img:max-w-full prose-img:h-auto
px-3 sm:px-6 py-4 sm:py-8">
<!-- Markdown content -->
<div [innerHTML]="markdownHTML"></div>
<!-- ToC (mobile: inline toggle) -->
<button *ngIf="headings.length > 0"
(click)="showToC = !showToC"
class="lg:hidden fixed bottom-20 right-4 p-3 rounded-full bg-blue-500 text-white shadow-lg">
📋
</button>
<nav *ngIf="showToC" class="lg:hidden fixed inset-0 bg-white dark:bg-gray-900
z-40 overflow-y-auto p-4">
<!-- ToC content -->
</nav>
</article>
```
### 6) ToC Drawer (Desktop Fixed, Mobile Inline)
```typescript
// app-toc-drawer.component.ts
@Component({
selector: 'app-toc-drawer',
template: `
<!-- Desktop: Fixed right panel (≥1024px) -->
<aside class="hidden lg:flex fixed right-0 top-14 bottom-0 w-64
bg-gray-50 dark:bg-gray-800 border-l
border-gray-200 dark:border-gray-700
flex-col overflow-y-auto">
<app-toc-content [headings]="headings"></app-toc-content>
</aside>
<!-- Mobile: Collapsible inline (< 1024px) -->
<div *ngIf="(isMobile$ | async)"
[@slideDown]="showTocMobile ? 'in' : 'out'"
class="bg-gray-50 dark:bg-gray-800 border-t p-3 max-h-96 overflow-y-auto">
<app-toc-content [headings]="headings"></app-toc-content>
</div>
`,
animations: [
trigger('slideDown', [
state('in', style({ height: '*' })),
state('out', style({ height: '0px' })),
transition('in <=> out', animate('200ms ease-in-out')),
]),
],
standalone: true,
})
export class AppTocDrawerComponent {
@Input() headings: Heading[] = [];
showTocMobile = false;
isMobile$ = this.breakpoint.observe('(max-width: 1023px)').pipe(
map(r => r.matches)
);
}
```
---
## 🎯 Livrables Attendus
### Code
1. **Toggle UI** : `UiModeService`, bouton navbar, `AppShellAdaptiveComponent`
2. **Responsive Wrappers** : Variants pour chaque composant (Desktop/Mobile)
3. **Mobile Components** : Bottom nav, drawer sidebar, inline ToC, mobile search
4. **Gesture Handling** : Swipe navigation directive, touch-friendly interactions
5. **Breakpoint Utilities** : Service CDK layout, reactive signals
### Styling
1. **Tailwind Config** : Breakpoints personnalisés, tokens tokens clair/sombre
2. **Mobile-First CSS** : Base mobile, enrichissements desktop via `md:`, `lg:`
3. **Touch-Friendly** : Boutons ≥44x44px, padding adéquat, hover states
### Documentation
1. **README_UI.md** : Schémas responsive, breakpoints, guide toggle
2. **MOBILE_GUIDE.md** : Navigation gestures, bottom nav flow, drawer patterns
3. **RESPONSIVE_CHECKLIST.md** : Tests par breakpoint, checklist A11y mobile
### Tests
1. **E2E** : Toggle persistence, layout switch, gesture navigation
2. **Visual Regression** : Screenshots desktop/tablet/mobile
3. **Accessibility** : Touch targets, ARIA labels, keyboard nav (Tab key)
---
## ⚡ Performance & Mobile Optimizations
### Critical Optimizations
- **Lazy-load images** : `loading="lazy"`, responsive `srcset`
- **Virtual scroll** : CDK virtual scroll adapté mobile (item height ≈ 7080px)
- **Debounce search** : 300ms sur mobile, 150ms sur desktop
- **Avoid layout shift** : Aspect ratios, skeleton loaders
- **Network awareness** : `navigator.connection.effectiveType` pour adapt qualité
- **Battery saver** : Réduire animations, throttle updates en mode saver
### Lighthouse Mobile Targets
- Performance ≥ 85
- Accessibility ≥ 95
- Best Practices ≥ 90
---
## 🎮 Raccourcis Clavier & Gestures
### Desktop
- `Ctrl/Cmd + K` : Palette commandes
- `Ctrl/Cmd + F` : Focus recherche
- `[` `]` : Replier/ouvrir ToC
- `Alt + ←/→` : Navigation historique
### Mobile/Tablet
- **Tap** : Ouvrir note/item
- **Swipe left/right** : Changer onglet (list → page → sidebar)
- **Long-press** : Menu contextuel (favoris, open in new tab)
- **Pull-to-refresh** : Rafraîchir liste (optionnel)
- **Double-tap** : Zoom ToC (mobile)
---
## 📋 Critères d'Acceptation
### Desktop (≥1024px)
- [x] Layout 3 colonnes (sidebar fixe/resizable, liste, page+ToC)
- [x] Changement dossier/tag/tri reflété en URL
- [x] 1000+ items fluide (60fps virtual scroll)
- [x] ToC synchronisé + repliable
- [x] Tous les flux clavier-seuls possibles
### Tablet (7681023px)
- [x] Navigation par onglets (Sidebar / List / Page)
- [x] Drawer sidebar (80vw, swipeable)
- [x] Bottom navigation sticky (4 icônes)
- [x] Contenu full-width par onglet
- [x] ToC inline collapsible
### Mobile (<768px)
- [x] Drawer sidebar (80vw max)
- [x] Bottom nav (4 onglets)
- [x] Search bar compact (menu + search + filters)
- [x] List items optimisés (titre + date + excerpt)
- [x] Markdown full-screen
- [x] ToC overlay ou inline toggle
- [x] Touch targets ≥ 44x44px
### Feature Flag
- [x] Toggle UI visible dans navbar
- [x] État persisté (localStorage)
- [x] Pas de perte d'état lors du switch
- [x] Legacy UI reste intacte
### Accessibility
- [x] WCAG 2.1 AA sur tous les breakpoints
- [x] Keyboard navigation complète (Tab, Arrow, Enter)
- [x] ARIA labels pour navigation tactile
- [x] Focus visible partout
- [x] Zoom ≤ 200% sans horizontal scroll
### Performance
- [x] TTI < 2.5s cold start
- [x] Scroll 60fps sur 1000+ items
- [x] Lighthouse Mobile ≥ 85 perf, ≥ 95 a11y
- [x] ImageOptimizations (lazy, srcset, format next-gen)
---
## 🗂️ Arborescence Fichiers
```
src/app/
├── layout/
│ ├── app-shell-adaptive/
│ │ └── app-shell-adaptive.component.ts # Feature flag wrapper
│ ├── app-shell-nimbus/
│ │ ├── app-shell-nimbus.component.ts # 3 colonnes (desktop)
│ │ ├── app-shell-nimbus.desktop.component.ts
│ │ └── app-shell-nimbus.mobile.component.ts
│ └── app-navbar/
│ ├── app-navbar.component.ts
│ └── [Bouton toggle UI intégré]
├── features/
│ ├── sidebar/
│ │ ├── app-left-sidebar.component.ts
│ │ ├── app-left-sidebar.desktop.component.ts
│ │ └── app-left-sidebar.mobile.component.ts
│ │
│ ├── search-bar/
│ │ ├── app-search-bar.component.ts
│ │ ├── app-search-bar.desktop.component.ts
│ │ └── app-search-bar.mobile.component.ts
│ │
│ ├── result-list/
│ │ ├── app-result-list.component.ts
│ │ ├── app-result-list.desktop.component.ts
│ │ ├── app-result-list.mobile.component.ts
│ │ └── app-result-list-item.component.ts
│ │
│ ├── note-view/
│ │ ├── app-note-view.component.ts
│ │ ├── app-note-view.desktop.component.ts
│ │ └── app-note-view.mobile.component.ts
│ │
│ ├── toc-drawer/
│ │ ├── app-toc-drawer.component.ts
│ │ └── app-toc-content.component.ts
│ │
│ └── bottom-nav/ [NEW]
│ ├── app-bottom-nav.component.ts
│ └── app-bottom-nav.component.html
├── shared/
│ ├── services/
│ │ ├── ui-mode.service.ts # [NEW] Toggle management
│ │ ├── mobile-nav.service.ts # [NEW] Tab/drawer state
│ │ └── breakpoint.service.ts # [NEW] Responsive helper
│ │
│ ├── directives/
│ │ └── swipe-nav.directive.ts # [NEW] Gesture detection
│ │
│ └── components/
│ └── resizable-handle/
└── styles/
├── tokens.css # Tailwind tokens
├── responsive.css # Breakpoint utilities
└── mobile.css # Mobile-specific (touches, etc.)
```
---
## 📅 Plan d'Implémentation (ordre conseillé)
1. **Feature Flag Infrastructure** (1-2j)
- `UiModeService` + localStorage persistence
- `AppShellAdaptiveComponent` wrapper
- Toggle button dans navbar
2. **Responsive Shell & Breakpoints** (2-3j)
- Desktop layout 3 colonnes (>=1024px)
- Tailwind breakpoints & tokens
- Resizable sidebar logic
3. **Mobile Navigation & Bottom Nav** (2-3j)
- `BottomNavComponent` (4 onglets)
- `MobileNavService` (state management)
- Tab/drawer routing
4. **Mobile Sidebar Drawer** (1-2j)
- Drawer animé (translate, backdrop)
- Swipe dismiss directive
- Z-index management
5. **Responsive Components** (3-4j)
- Search bar variants (desktop/mobile)
- Result list item responsive
- Markdown viewer mobile optimizations
6. **ToC Drawer Adaptive** (1-2j)
- Fixed right panel (desktop)
- Inline toggle (mobile)
- Animations smooth
7. **Gestures & Touch** (1-2j)
- Swipe nav directive
- Long-press menu
- Pull-to-refresh (optionnel)
8. **Accessibility & Testing** (2-3j)
- WCAG 2.1 AA audit
- Keyboard nav (Tab, Arrow)
- E2E tests (toggle, breakpoints)
- Visual regression (3 breakpoints)
**Total estimé** : 1321 jours (équipe 1 FE engineer)
---
## 🚀 Scripts NPM
```bash
# Dev complet (Nimbus activé par défaut)
npm run dev
# Build production
npm run build
# Tests responsifs (plusieurs breakpoints)
npm run test:responsive
# Lighthouse audit mobile
npm run audit:lighthouse:mobile
# Feature flag (override)
NIMBUS_UI=false npm run dev # Force legacy UI
```
---
## ✅ Checklist Livraison
- [ ] Toggle UI visible, fonctionnel, persisté
- [ ] Desktop (≥1024px) : 3 colonnes, interactions fluides
- [ ] Tablet (7681023px) : Onglets + drawer, full-width contenu
- [ ] Mobile (<768px) : Bottom nav, drawer, touch-friendly
- [ ] Tous les flux clavier-seuls réalisables
- [ ] Lighthouse mobile ≥ 85 perf, ≥ 95 a11y
- [ ] Virtual scroll 60fps sur 1000+ items
- [ ] Tests E2E (toggle, breakpoints, gestures)
- [ ] Documentation complète (README_UI.md, MOBILE_GUIDE.md, RESPONSIVE_CHECKLIST.md)
- [ ] Zéro régression : legacy UI inchangée, Wikilinks, bookmarks, graph intacts
- [ ] Screenshots before/after 3 breakpoints
---
## 📖 Documentation à Produire
1. **README_UI.md** : Overview, architecture, screenshots 3 breakpoints
2. **MOBILE_GUIDE.md** : Navigation onglets, gestures, drawer patterns
3. **RESPONSIVE_CHECKLIST.md** : Tests par breakpoint, device testing
4. **DEPLOYMENT.md** : Feature flag pour bascule progressive
5. **ARCHITECTURE_DIAGRAM.md** : Schémas adaptatifs (Mermaid)
---
## 💡 Notes Importantes
- **Mobile First** : Développer pour mobile en premier, puis enrichir desktop.
- **Persistent State** : Le toggle UI et les filtres actifs doivent persister via localStorage (sans browser storage, utiliser sessionStorage ou service state).
- **Zero Regression** : L'ancienne interface reste intacte et fonctionnelle.
- **Performance** : Virtual scroll adapté mobile (40+ items à l'écran), lazy-load images.
- **Accessibility** : 44x44px touch targets minimum, ARIA labels complets, keyboard nav.
- **Testing** : Visual regression sur breakpoints clés (375px / 768px / 1440px).
---
**Exécute maintenant ce plan** : crée les composants, adapte les routes/états, ajoute les styles Tailwind responsifs, branche la recherche et livre le MR conforme aux critères ci-dessus avec toggle UI et compatibilité 100% Desktop/Mobile.

View File

@ -0,0 +1,283 @@
Voici une version *prête à coller dans Windsurf* qui intègre fidèlement linterface Nimbus/FuseBase **et** garantit une compatibilité à 100 % Desktop + Mobile (téléphone + tablette). Jai resserré, clarifié et relié chaque exigence aux patterns “Nimbus” (chips filtrants, pickers Clear/Done, outline latéral, Portals/Share, workspaces, etc.).
---
# 🎯 Prompt Windsurf — ObsiViewer « Nimbus UI » (Desktop + Mobile 100%)
## Rôle & Autorité
Agis comme **Staff Frontend Engineer Angular 20 + UX Designer**. Raisonnement détaillé **autorisé**. Tu peux refactorer, introduire de nouveaux composants, migrer le CSS vers **Tailwind**, et **ne brise aucune feature** existante.
**Garde-fous**
* **Feature flag** : un **toggle** dans la navbar bascule *Nimbus UI**Legacy UI* **sans perte détat** (URL, sélection, filtres).
* **100 % Responsive** : Desktop, Tablet, Mobile (petits smartphones inclus).
* **A11y** : WCAG 2.1 AA, clavier + écran tactile.
---
## ADN Nimbus à reproduire (invariants UX)
1. **3 panneaux stables** : Nav gauche (Quick Links / Folders / Tags), Index central (Recherche + chips **All folders ▾ / All tags ▾ / All pages ▾**), Page à droite (markdown + **outline ToC** dockable).
2. **Recherche dabord** : top bar centrée, **icône filtre** → options avancées.
3. **Chips persistantes** = *stateful filters* (caret + **badges comptage** + Clear/Done).
4. **Pickers riches** (dossiers hiérarchiques multi-sélection, tags à coches, **barre de recherche locale**).
5. **Progressive disclosure** : menus condensés, pickers/overlays, **hover-reveal “+”** pour créer un sous-dossier.
6. **Workspaces** strictement séparés ; **Share** et **Add to portal** accessibles depuis la barre daction de la page (si disponibles).
7. **Contenu riche** : markdown, callouts, code, **cartes Bookmark** (titre/desc/vignette).
8. **Outline contextuel** : bouton rond “hamburger” flottant dans la page → rail ToC H1H6 avec **scroll-to**.
> Référence de conception : Folders/Tags bi-axial, chips visibles en permanence, *Clear partout*, hiérarchie typographique nette, dark/light cohérents.
---
## Objectif Final (résumé)
* **Desktop (≥ 1024px)** : Layout **3 colonnes** (sidebar resizable 240440px / index virtualisé / page + ToC fixe à droite).
* **Tablet (7681023px)** : **Bottom tabs** (Sidebar • List • Page • ToC) + **drawer** pour la sidebar.
* **Mobile (< 768px)** : **Bottom nav** (4 icônes), sidebar en **drawer 80vw**, ToC **inline/drawer**, gestes **swipe** pour naviguer entre onglets.
---
## Feature Flag & Toggle (obligatoire)
* **UiModeService** (signal boolean, persistance `localStorage: obsiviewer-ui-mode = nimbus|legacy`).
* **AppShellAdaptiveComponent** sélectionne *Nimbus* vs *Legacy*.
* **Bouton toggle** dans la navbar, accessible (`aria-label`) et **sans reset de létat** (on conserve : filtres actifs, élément sélectionné, scrolls, URL).
---
## Responsive Design — Stratégie
* **Mobile-first** avec Tailwind (`xs, sm, md, lg, xl, 2xl`).
* **Variants par composant** : `*.desktop.component` (≥ lg) / `*.mobile.component` (< lg).
* **Breakpoints cdk/layout** pour linjection conditionnelle.
* **Touch targets ≥ 44×44px**, densité **compacte mais respirante** (Nimbus-style).
---
## Composants à livrer (Nimbus-compat)
1. **Left Sidebar** (desktop fixe/resizable, mobile drawer)
* Sections : Quick Links, **Folders** (arbo + *hover-reveal “+”*), **Tags**, Trash.
* **Workspace switcher** + **theme switch** via menu avatar en bas.
2. **Center List**
* **Search bar** (champ centré + icône filtre)
* **Chips** : All folders ▾ / All tags ▾ / All pages ▾ (badges + caret)
* **Pickers overlays** :
* **Folders** multi-sélection hiérarchique, recherche locale, **Clear/Done**, badges *+N*.
* **Tags** alphabétique, **checkmarks**, Clear/Done.
* **Liste virtualisée** (CDK) : titre, date grisée, **snippet** (line-clamp), petites icônes (ex. bookmark).
* État : “Found pages: N” + **Clear** visible si filtres actifs.
3. **Note View + ToC**
* Page markdown (prose), **barre dactions** à droite : **Ask AI**, **Add to portal**, **Share**, loupe “find in page”, attachements, **plein écran**.
* **ToC Drawer** : fixe à droite (desktop) ; **inline/drawer** (mobile).
* **Bouton flottant ToC** (rond) *dans* la page.
* **Cards Bookmark** (preview URL).
4. **Mobile Shell**
* **Bottom navigation** (Sidebar / List / Page / ToC).
* **Gestures** : swipe gauche/droite pour changer donglet, pull-to-refresh (optionnel), long-press menu contextuel.
* **Search compact** (menu, champ, bouton filtres → popover).
---
## Exigences Techniques Clés
* **URL state** : sélection dossier/tag/tri dans lURL (deep link).
* **Persistences** : chips actives, split sizes, dernier onglet mobile, thème, workspace.
* **Virtual scroll** : item 7080px, 60 fps sur 1000+ items.
* **Dark/Light** : palette stable, **contrastes sûrs** (Nimbus dark très contrasté).
* **Overlays** : pickers centrés, **Clear/Done** persistants en pied, focus trap + ESC.
* **Perf Mobile** : debounce recherche (300 ms mobile / 150 ms desktop), images lazy, évite CLS (skeletons, `aspect-[ratio]`).
* **A11y** : ARIA, focus visible, nav clavier complète (Tab/Shift+Tab, Arrow), *skip links*.
---
## Livrables (code & docs)
**Code**
1. `UiModeService`, bouton navbar, `AppShellAdaptiveComponent`.
2. Variants responsive : `left-sidebar`, `center-list`, `note-view`, `toc-drawer`, `search-bar`.
3. **BottomNav**, **MobileNavService**, **SwipeNavDirective**.
4. **Pickers** (Folders/Tags) avec recherche locale + Clear/Done.
5. **Resizable handle** (sidebar), **virtual scroll** (index).
**Styling**
* `tailwind.config.js` (breakpoints), tokens light/dark, classes utilitaires mobile-first.
* Prose markdown responsive, badges/chips Nimbus-like, states *hover/selected*.
**Docs**
* `README_UI.md` (diagrammes 3 breakpoints + captures).
* `MOBILE_GUIDE.md` (flow onglets, gestes, drawer).
* `RESPONSIVE_CHECKLIST.md` (tests par breakpoint + devices).
* `DEPLOYMENT.md` (feature flag rollout).
**Tests**
* E2E : toggle persistant, switch sans perte détat, pickers Clear/Done, deep links.
* Visuel : snapshots Desktop/Tablet/Mobile.
* A11y : axe + audits clavier.
* Perf : 60 fps scroll, TTI < 2.5 s (mobile cold), Lighthouse Mobile 85 / A11y 95.
---
## Critères dAcceptation (DoD)
**Desktop (≥ 1024px)**
* [x] 3 colonnes, sidebar **resizable**, ToC fixe à droite.
* [x] Chips visibles + pickers overlays Clear/Done, **badges comptage**.
* [x] 1000+ items fluide (virtual scroll 60 fps).
* [x] *Ask AI / Add to portal / Share* visibles si feature activée.
**Tablet (7681023px)**
* [x] **Bottom tabs** + sidebar **drawer** (swipe).
* [x] ToC **inline** repliable.
* [x] Tous contenus **full-width** par onglet.
**Mobile (< 768px)**
* [x] **Bottom nav** (4 onglets), sidebar **drawer 80vw**.
* [x] Search compact + popover filtres, badges actifs scrollables en horizontal.
* [x] Markdown **full-screen**, ToC overlay/inline toggle.
* [x] Touch targets ≥ 44×44px.
**Feature Flag & A11y/Perf**
* [x] Toggle visible, persistant, **sans perte détat**.
* [x] WCAG 2.1 AA, focus visible, ARIA.
* [x] Lighthouse Mobile ≥ 85 perf, ≥ 95 a11y.
---
## Plan dImplémentation (ordre conseillé)
1. **Feature Flag infra** (UiModeService + AppShellAdaptive + toggle navbar).
2. **Shell Responsive** (3 colonnes desktop, Tailwind tokens, resizable sidebar).
3. **Mobile Navigation** (BottomNav + MobileNavService + routing/états).
4. **Sidebar Drawer** (anim, backdrop, swipe dismiss, z-index).
5. **Pickers** (Folders/Tags) + chips/overlays + Clear/Done + recherche locale.
6. **ToC Drawer** (fixe desktop / inline mobile) + bouton flottant.
7. **Perf & A11y** (virtual scroll, debounce, lazy, focus trap).
8. **Tests & Docs** (E2E, visuel, a11y, guides).
---
## Squelette de code minimal (extraits)
### Toggle UI (navbar)
```html
<button (click)="ui.toggleUIMode()"
[attr.aria-label]="'Toggle ' + (ui.isNimbusMode() ? 'legacy' : 'nimbus') + ' UI'"
class="p-2 rounded hover:bg-gray-100 dark:hover:bg-gray-800">
<span *ngIf="ui.isNimbusMode()">✨ Nimbus</span>
<span *ngIf="!ui.isNimbusMode()">🔧 Legacy</span>
</button>
```
### Shell adaptatif
```ts
@Component({
selector: 'app-shell-adaptive',
template: `
@if (ui.isNimbusMode()) { <app-shell-nimbus/> } @else { <app-shell-legacy/> }
`,
standalone: true,
imports: [AppShellNimbusComponent, AppShellLegacyComponent]
})
export class AppShellAdaptiveComponent { constructor(public ui: UiModeService) {} }
```
### Chips + Pickers (pattern)
```html
<!-- Chips persistants -->
<div class="flex gap-2 flex-wrap">
<app-chip [label]="foldersLabel" (click)="openFoldersPicker()"></app-chip>
<app-chip [label]="tagsLabel" (click)="openTagsPicker()"></app-chip>
<app-chip [label]="pagesLabel" (click)="openPagesPicker()"></app-chip>
</div>
<!-- Overlay picker Folders (multi + Clear/Done + search locale) -->
<app-folders-picker *ngIf="showFolders"
[selected]="selectedFolders"
(search)="onLocalSearch($event)"
(clear)="clearFolders()" (done)="applyFolders($event)">
</app-folders-picker>
```
### Bottom Nav (mobile)
```html
<nav class="fixed bottom-0 inset-x-0 h-16 md:hidden
bg-white dark:bg-gray-900 border-t border-gray-200 dark:border-gray-800
flex justify-around z-30">
<button *ngFor="let t of tabs" (click)="setTab(t.id)"
class="flex-1 flex flex-col items-center justify-center text-xs gap-1">
<span class="text-lg">{{t.icon}}</span><span>{{t.label}}</span>
</button>
</nav>
```
---
## Arborescence proposée
```
src/app/
├─ layout/
│ ├─ app-shell-adaptive/
│ ├─ app-shell-nimbus/ (desktop/mobile variants)
│ └─ app-navbar/
├─ features/
│ ├─ sidebar/ (desktop + mobile drawer)
│ ├─ search-bar/ (desktop + mobile)
│ ├─ center-list/ (+ virtual scroll + chips + pickers)
│ ├─ note-view/ (+ toolbar AskAI/Share/Portal si activées)
│ └─ toc-drawer/ (desktop fixe / mobile inline)
├─ shared/
│ ├─ services/ (ui-mode, mobile-nav, breakpoint)
│ ├─ directives/ (swipe-nav)
│ └─ components/ (resizable-handle, chip, picker, badge)
└─ styles/ (tokens, responsive, mobile)
```
---
## Raccourcis & Gestes
* **Desktop** : `Ctrl/Cmd+K` palette, `Ctrl/Cmd+F` recherche, `Alt+←/→` historique, `[` `]` ToC.
* **Mobile** : **swipe** onglet précédent/suivant, **long-press** menu item, **tap** ouvre note, **pull-to-refresh** (optionnel).
---
## Cibles Perf & Qualité
* **TTI** < 2.5 s sur mobile cold.
* **60 fps** scroll 1000+ items.
* **CLS** < 0.1 (skeletons, ratios).
* **Lighthouse Mobile** ≥ 85 (Perf) / ≥ 95 (A11y).
---
## Consignes supplémentaires
* **Zéro régression** : graph view, wikilinks, bookmarks, search operators fonctionnels.
* **Internationalisation** prête (labels chips, Clear/Done).
* **State durable** : localStorage ou service (fallback SSR).
* **Thèmes** : switch Light/Dark depuis avatar footer (comme Nimbus).
---
**Exécute ce plan** : implémente le *Nimbus UI* responsive avec toggle, livre le MR complet (code + tests + docs), conforme aux critères ci-dessus, Desktop/Tablet/Mobile **100 % OK**.

View File

@ -0,0 +1,481 @@
Voici le prompt refondu pour inclure la compatibilité mobile/tablet complète tout en conservant la philosophie Nimbus :
# 🎯 Prompt Windsurf — ObsiViewer Nimbus UI (Desktop + Mobile)
## ObsiViewer → UI/UX "Nimbus-like" (responsive, dense, rapide)
**Rôle & mode :** Agis comme **Staff Frontend Engineer Angular 20 + UX designer**. Raisonnement détaillé autorisé. Tu as les pleins pouvoirs de refactor UI, d'ajout de composants, et de migration CSS vers Tailwind. Conserve la compatibilité de toutes features existantes.
**Contrainte majeure :** L'interface doit être **100% responsive** (Desktop ≥1024px / Tablet 768-1023px / Mobile <768px). Un **bouton toggle** dans la navbar permet de basculer entre l'ancienne interface et la nouvelle sans perte d'état.
---
## 📋 Architecture Nimbus Responsive
### Desktop (≥1024px) - Layout 3 colonnes
```
┌─────────────────────────────────────────────────────────┐
│ NAVBAR (Search centré + CTA "+ Page" + Actions droite) │
├─────────────┬─────────────────────┬─────────────────────┤
│ SIDEBAR │ CENTER COLUMN │ NOTE + TOC │
│ Navigation │ • Chips filtres │ • Édition riche │
│ Dossiers/Tags│ • Liste résultats │ • Outline contextuel│
│ Quick Links │ • Virtual scroll │ • Barre actions │
└─────────────┴─────────────────────┴─────────────────────┘
```
### Tablet (768-1023px) - Navigation par onglets
```
┌────────────────────────────────────┐
│ NAVBAR (Search + Toggle UI) │
├────────────────────────────────────┤
│ [≡] [📄] [🔍] [📋] Tabs bottom │
├────────────────────────────────────┤
│ │
│ CONTENU ACTIF FULL-WIDTH │
│ • Sidebar: Drawer 80vw │
│ • Liste: Cards compactes │
│ • Note: Markdown + ToC inline │
│ │
└────────────────────────────────────┘
```
### Mobile (<768px) - Navigation bottom + Drawers
```
┌──────────────────────────────────┐
│ NAVBAR compacte (Menu + Search) │
├──────────────────────────────────┤
│ CONTENT AREA │
│ • Sidebar: Drawer full │
│ • Liste: Items optimisés │
│ • Note: Plein écran │
├──────────────────────────────────┤
│ [≡][📄][+][🔍][📋] Bottom Nav │
└──────────────────────────────────┘
```
---
## 🎯 Composants Nimbus Spécifiques à Reproduire
### 1) Top Bar Nimbus (Responsive)
```typescript
// Desktop: Search centré + CTA turquoise
<header class="flex items-center justify-between p-4">
<!-- Gauche: Logo/Worspace -->
<div class="w-1/4">Workspace Selector</div>
<!-- Centre: Search large + filtre -->
<div class="flex-1 max-w-2xl">
<div class="relative">
<input type="text" placeholder="Search..." class="w-full pl-10 pr-4 py-2 rounded-lg border">
<span class="absolute left-3 top-2.5">🔍</span>
<button class="absolute right-3 top-2.5"></button>
</div>
</div>
<!-- Droite: CTA + Actions -->
<div class="w-1/4 flex justify-end gap-2">
<button class="bg-cyan-500 text-white px-4 py-2 rounded-lg">+ Page</button>
<button>Ask AI</button>
<button>Share</button>
</div>
</header>
// Mobile: Stacked + icons
<header class="p-3 space-y-2">
<div class="flex justify-between">
<button></button>
<button class="bg-cyan-500 text-white px-3 py-1 rounded">+</button>
</div>
<div class="relative">
<input type="text" placeholder="Search..." class="w-full pl-8 pr-3 py-1 rounded border">
<span class="absolute left-2 top-1.5">🔍</span>
</div>
</header>
```
### 2) Chips de Filtres Nimbus (Responsive)
```typescript
// Desktop: Chips horizontales
<div class="flex gap-2 p-4 border-b">
<div class="chip-filter">
<span>All folders</span>
<span class="badge">+2</span>
<span></span>
</div>
<div class="chip-filter">
<span>All tags</span>
<span class="badge">+1</span>
<span></span>
</div>
<div class="chip-filter">
<span>All pages</span>
<span></span>
</div>
</div>
// Mobile: Chips scrollables horizontalement
<div class="flex gap-1 p-3 border-b overflow-x-auto">
<div class="chip-filter flex-shrink-0">
<span>Folders</span>
<span></span>
</div>
<div class="chip-filter flex-shrink-0">
<span>Tags</span>
<span></span>
</div>
<!-- ... -->
</div>
```
### 3) Picker Overlays Nimbus (Responsive)
```typescript
// Desktop: Overlay centré
<div class="fixed inset-0 bg-black/20 z-50 flex items-start justify-center pt-20">
<div class="bg-white rounded-lg shadow-xl w-96 max-h-96 overflow-hidden">
<!-- Header avec recherche -->
<div class="p-3 border-b">
<input type="text" placeholder="Search folders..." class="w-full p-2 border rounded">
</div>
<!-- Liste avec hiérarchie -->
<div class="overflow-y-auto max-h-64">
<div class="flex items-center p-2 hover:bg-gray-100">
<input type="checkbox" class="mr-2">
<span>📁</span>
<span class="ml-2 flex-1">Workspace</span>
<span></span>
</div>
<!-- Sous-dossiers indentés -->
<div class="flex items-center p-2 pl-6 hover:bg-gray-100">
<input type="checkbox" class="mr-2">
<span>📁</span>
<span class="ml-2 flex-1">Projects</span>
<span class="text-xs text-gray-500">15</span>
</div>
</div>
<!-- Footer actions -->
<div class="flex justify-between p-3 border-t">
<button class="text-gray-600">Clear</button>
<button class="bg-cyan-500 text-white px-4 py-1 rounded">Done</button>
</div>
</div>
</div>
// Mobile: Picker full-screen
<div class="fixed inset-0 bg-white z-50">
<div class="p-4 border-b flex justify-between items-center">
<h3 class="font-semibold">Select Folders</h3>
<button class="text-cyan-500">Done</button>
</div>
<div class="p-3 border-b">
<input type="text" placeholder="Search folders..." class="w-full p-2 border rounded">
</div>
<div class="overflow-y-auto h-full pb-20">
<!-- Liste mobile-optimisée -->
</div>
</div>
```
### 4) Outline Contextuel Nimbus (Responsive)
```typescript
// Desktop: Panneau droit fixe
<aside class="fixed right-0 top-14 bottom-0 w-64 border-l bg-gray-50 overflow-y-auto hidden lg:block">
<div class="p-4">
<h4 class="font-semibold mb-3">Outline</h4>
<nav class="space-y-1">
<a class="block py-1 text-sm text-gray-600 hover:text-gray-900"># Introduction</a>
<a class="block py-1 pl-4 text-sm text-gray-600 hover:text-gray-900">## Getting Started</a>
<!-- ... -->
</nav>
</div>
</aside>
// Mobile: Bouton flottant + overlay
<button class="fixed bottom-20 right-4 w-12 h-12 bg-cyan-500 text-white rounded-full shadow-lg lg:hidden"
(click)="showTocMobile = true">
📋
</button>
<div *ngIf="showTocMobile" class="fixed inset-0 bg-white z-50 lg:hidden">
<div class="p-4 border-b flex justify-between">
<h3 class="font-semibold">Table of Contents</h3>
<button (click)="showTocMobile = false"></button>
</div>
<div class="p-4 overflow-y-auto h-full">
<!-- Contenu ToC -->
</div>
</div>
```
---
## 🎨 Palette Nimbus & Design Tokens
```css
/* Tokens Nimbus (light/dark) */
:root {
/* Couleurs primaires */
--nimbus-cyan: #06b6d4;
--nimbus-cyan-dark: #0891b2;
/* Gris scale */
--nimbus-gray-50: #f9fafb;
--nimbus-gray-100: #f3f4f6;
--nimbus-gray-800: #1f2937;
--nimbus-gray-900: #111827;
/* Espacements */
--nimbus-space-1: 0.25rem;
--nimbus-space-2: 0.5rem;
--nimbus-space-3: 0.75rem;
/* Typographie */
--nimbus-text-sm: 0.875rem;
--nimbus-text-base: 1rem;
}
.dark {
--nimbus-bg: var(--nimbus-gray-900);
--nimbus-surface: var(--nimbus-gray-800);
}
```
---
## 📱 Gestes Mobiles Spécifiques Nimbus
### Swipe Navigation
```typescript
@Directive({
selector: '[appSwipeNav]',
standalone: true
})
export class SwipeNavDirective {
private startX = 0;
private startY = 0;
@HostListener('touchstart', ['$event'])
onTouchStart(e: TouchEvent) {
this.startX = e.touches[0].clientX;
this.startY = e.touches[0].clientY;
}
@HostListener('touchend', ['$event'])
onTouchEnd(e: TouchEvent) {
const endX = e.changedTouches[0].clientX;
const endY = e.changedTouches[0].clientY;
const diffX = this.startX - endX;
const diffY = this.startY - endY;
// Seulement swipe horizontal significatif
if (Math.abs(diffX) > 50 && Math.abs(diffY) < 30) {
if (diffX > 0) {
this.swipeLeft.emit(); // → Tab suivant
} else {
this.swipeRight.emit(); // ← Tab précédent
}
}
}
@Output() swipeLeft = new EventEmitter<void>();
@Output() swipeRight = new EventEmitter<void>();
}
```
### Hover-reveal Adaptatif (Desktop seulement)
```typescript
// Seulement sur desktop
<div class="group relative">
<div class="flex items-center">
<span>📁 Projects</span>
<button class="opacity-0 group-hover:opacity-100 transition-opacity lg:block hidden ml-2">
+
</button>
</div>
</div>
// Mobile: Toujours visible ou menu contextuel
<div class="flex items-center justify-between lg:justify-start">
<span>📁 Projects</span>
<button class="lg:hidden ml-2">+</button>
</div>
```
---
## 🔧 Service UI Mode & Responsive State
```typescript
@Injectable({ providedIn: 'root' })
export class UiModeService {
// Signal pour le mode Nimbus vs Legacy
isNimbusMode = signal<boolean>(this.loadUIMode());
// Signal pour le breakpoint actif
currentBreakpoint = signal<'mobile' | 'tablet' | 'desktop'>('desktop');
constructor(private breakpointObserver: BreakpointObserver) {
// Surveillance des breakpoints
this.breakpointObserver.observe([
'(max-width: 767px)',
'(min-width: 768px) and (max-width: 1023px)',
'(min-width: 1024px)'
]).subscribe(result => {
const breakpoints = result.breakpoints;
if (breakpoints['(max-width: 767px)']) {
this.currentBreakpoint.set('mobile');
} else if (breakpoints['(min-width: 768px) and (max-width: 1023px)']) {
this.currentBreakpoint.set('tablet');
} else {
this.currentBreakpoint.set('desktop');
}
});
}
toggleUIMode() {
const newMode = !this.isNimbusMode();
this.isNimbusMode.set(newMode);
localStorage.setItem('obsiviewer-ui-mode', newMode ? 'nimbus' : 'legacy');
}
private loadUIMode(): boolean {
return localStorage?.getItem('obsiviewer-ui-mode') !== 'legacy';
}
}
```
---
## 🚀 Composants Spécifiques Nimbus
### 1) Bookmark Card (Responsive)
```typescript
// Desktop: Carte horizontale
<div class="border rounded-lg p-3 hover:shadow-md transition-shadow">
<div class="flex gap-3">
<img src="thumbnail.jpg" class="w-20 h-20 rounded object-cover flex-shrink-0">
<div class="flex-1 min-w-0">
<h4 class="font-semibold truncate">Article Title</h4>
<p class="text-sm text-gray-600 line-clamp-2">Description of the bookmarked content...</p>
<div class="flex items-center gap-2 mt-1">
<span class="text-xs text-gray-500">example.com</span>
<span class="text-xs text-gray-500">2 days ago</span>
</div>
</div>
</div>
</div>
// Mobile: Carte verticale
<div class="border rounded-lg p-3 hover:shadow-md transition-shadow">
<img src="thumbnail.jpg" class="w-full h-32 rounded object-cover mb-2">
<h4 class="font-semibold truncate">Article Title</h4>
<p class="text-sm text-gray-600 line-clamp-2">Description...</p>
<div class="flex justify-between items-center mt-2">
<span class="text-xs text-gray-500">example.com</span>
<span class="text-xs text-gray-500">2 days ago</span>
</div>
</div>
```
### 2) Result List Item Nimbus
```typescript
// Desktop: Ligne compacte
<div class="flex items-center gap-3 p-3 border-b hover:bg-gray-50 cursor-pointer">
<div class="w-6 h-6 rounded bg-blue-100 flex items-center justify-center text-sm">📄</div>
<div class="flex-1 min-w-0">
<h4 class="font-medium truncate">Document Title</h4>
<p class="text-sm text-gray-600 truncate">First few lines of content as preview...</p>
</div>
<div class="flex items-center gap-3 text-sm text-gray-500">
<span>2h ago</span>
<div class="flex gap-1">
<span class="bg-gray-100 px-2 py-0.5 rounded text-xs">work</span>
</div>
</div>
</div>
// Mobile: Stack vertical
<div class="p-3 border-b hover:bg-gray-50 cursor-pointer">
<div class="flex items-start gap-2">
<div class="w-6 h-6 rounded bg-blue-100 flex items-center justify-center text-sm mt-0.5">📄</div>
<div class="flex-1 min-w-0">
<h4 class="font-medium">Document Title</h4>
<p class="text-sm text-gray-600 line-clamp-2">First few lines of content as preview...</p>
<div class="flex items-center justify-between mt-1">
<span class="text-xs text-gray-500">2h ago</span>
<div class="flex gap-1">
<span class="bg-gray-100 px-2 py-0.5 rounded text-xs">work</span>
</div>
</div>
</div>
</div>
</div>
```
---
## 📋 Critères d'Acceptation Nimbus
### Desktop (≥1024px)
- [x] **Layout 3 colonnes** fidèle à Nimbus
- [x] **Top bar** avec search centré + CTA "+ Page" turquoise
- [x] **Chips filtres** "All folders ▾", "All tags ▾", "All pages ▾" avec badges
- [x] **Pickers overlays** avec recherche locale + hiérarchie
- [x] **Outline contextuel** panneau droit fixe
- [x] **Hover-reveal** création sous-dossiers
- [x] **Workspace switcher** dans sidebar
### Tablet (768-1023px)
- [x] **Navigation par onglets** [Sidebar] [List] [Page] [ToC]
- [x] **Drawer sidebar** 80vw avec arborescence
- [x] **Chips scrollables** horizontalement
- [x] **Pickers full-screen** avec Done/Clear
- [x] **ToC inline** collapsible
### Mobile (<768px)
- [x] **Bottom navigation** 5 onglets [Menu] [List] [+] [Search] [ToC]
- [x] **Drawers full-width** pour sidebar/pickers
- [x] **Search bar compacte** dans header
- [x] **Touch targets** ≥ 44px
- [x] **Swipe gestures** changement onglets
- [x] **Pull-to-refresh** liste résultats
### Fidélité Nimbus
- [x] **Philosophie workspace-first** avec sélecteur d'espace
- [x] **Organisation bi-axiale** dossiers + tags
- [x] **Recherche d'abord** avec filtres persistants
- [x] **Progressive disclosure** (menus contextuels)
- [x] **Bookmarks** avec cartes enrichies
- [x] **Boutons Share/Add to portal** visibles
### Performance & Accessibilité
- [x] **Virtual scroll** 1000+ items fluide
- [x] **Lighthouse Mobile** ≥ 85 perf, ≥ 95 a11y
- [x] **Keyboard navigation** complète
- [x] **WCAG 2.1 AA** tous breakpoints
- [x] **Toggle UI** persisté sans perte état
---
## 🎯 Livrables Exacts
1. **Toggle UI Nimbus/Legacy** avec persistence
2. **Layout 3 colonnes desktop** fidèle Nimbus
3. **Navigation responsive** tablette/mobile
4. **Composants Nimbus** : Chips, Pickers, Outline, Bookmark cards
5. **Gestes mobiles** : swipe, pull-to-refresh
6. **Thème clair/sombre** Nimbus-like
7. **Documentation** responsive + patterns Nimbus
**État initial** : Toggle sur "Nimbus" par défaut, legacy UI intacte
**Testing** : 3 breakpoints + gestures + accessibility
**Performance** : 60fps virtual scroll, lazy loading images
---
Exécute maintenant cette implémentation en respectant scrupuleusement les patterns UI/UX de Nimbus Notes tout en garantissant la compatibilité 100% responsive mobile/tablet/desktop.

View File

@ -0,0 +1,214 @@
Absolument. Voici une version refondue et enrichie du prompt. Elle intègre la philosophie et les détails UX de l'analyse de Nimbus Notes directement dans les spécifications techniques pour le développement de ObsiViewer, tout en renforçant l'exigence d'une compatibilité parfaite entre Desktop et Mobile.
Ce prompt est conçu pour être donné directement à une équipe de développement.
-----
# 🎯 Prompt Windsurf — Refonte UI/UX "Nimbus-like" pour ObsiViewer (Desktop + Mobile)
## 👤 Rôle & Mode
Agis comme **Staff Frontend Engineer Angular 20 + UX Designer**. Tu as les pleins pouvoirs pour refondre l'UI, ajouter les composants nécessaires et migrer le CSS vers Tailwind. Ton raisonnement doit être détaillé et toutes les features existantes doivent rester fonctionnelles.
## 📜 Philosophie & Principes Directeurs (Inspiré de Nimbus/FuseBase)
L'objectif n'est pas juste de changer l'apparence, mais d'adopter une philosophie qui rend l'application plus intuitive et puissante.
1. **Trois Panneaux Stables (Desktop)** : La structure principale est claire : Navigation à gauche, Liste des résultats au centre, Contenu à droite. Sur mobile, ces panneaux deviennent des vues ou des drawers distincts.
2. **Filtres Persistants & Visibles** : La recherche est affinée via des "chips" (ex: `All folders ▾`) toujours visibles. L'état du filtre est un élément central de l'UI, pas un menu caché.
3. **Pickers Riches** : Cliquer sur un chip de filtre ouvre un overlay (picker) avec sa propre recherche interne, des sélections multiples et des actions claires (`Clear`/`Done`).
4. **Découverte Progressive (Progressive Disclosure)** : Les options complexes sont masquées jusqu'à ce qu'elles soient nécessaires (ex: le bouton `+` pour ajouter un sous-dossier au survol, le sommaire/ToC qui s'ouvre depuis un bouton flottant).
5. **Création Centralisée** : L'action de création principale (`+ Page`) est unique et toujours accessible au même endroit.
6. **Organisation Bi-Axiale** : L'utilisateur navigue via une **hiérarchie de dossiers** (structure) et des **tags transversaux** (contexte).
7. **Le Contenu est Roi** : La lisibilité est maximisée (hiérarchie de titres, marges, etc.) et le contenu peut être enrichi (cartes de bookmarks, etc.).
8. **Réinitialisation Facile** : Des options "Clear" sont omniprésentes pour annuler les filtres et recherches, encourageant l'exploration sans crainte de se perdre.
## 🚀 Contrainte Majeure
L'interface doit être **100% responsive et optimisée pour chaque format (Desktop, Tablette, Mobile)**. Un **bouton de bascule** dans la barre de navigation permettra de passer de l'ancienne interface à la nouvelle ("Nimbus mode") sans perte d'état, avec une persistance du choix dans `localStorage`.
-----
## 🎯 Objectif Final
### Desktop (≥1024px)
Refondre ObsiViewer en une interface à **3 colonnes resizables** :
1. **Sidebar Gauche** : Accès rapides, arborescence de dossiers, liste de tags.
2. **Colonne Centrale** : Barre de recherche principale, trio de **chips de filtres** (`Dossiers`, `Tags`, `Pages`), et la liste des résultats virtualisée.
3. **Panneau Droit** : Lecteur Markdown avec une barre d'actions et un **panneau de sommaire (ToC)** accessible via un bouton flottant à droite.
### Tablette & Mobile (\<1024px)
Transformer l'interface en une navigation par **onglets en bas de l'écran (Bottom Navigation)** ou via un **drawer latéral**.
- **Vue 1 (Navigation)** : Accès aux dossiers et tags (drawer ou vue dédiée).
- **Vue 2 (Liste)** : Barre de recherche et résultats en pleine largeur.
- **Vue 3 (Page)** : Lecteur Markdown en pleine largeur.
- **Gestures** : Le swipe horizontal permet de naviguer entre les vues ; le pull-to-refresh actualise les listes.
-----
## 📋 Architecture du Feature Flag
### 1\) Toggle UI dans la NavBar (`app-navbar.component.html`)
Ajouter un bouton clair pour basculer entre les modes.
```html
<button (click)="uiModeService.toggleUIMode()"
[attr.aria-label]="'Basculez vers l\'interface ' + ((uiModeService.isNimbusMode$ | async) ? 'Legacy' : 'Nimbus')"
class="p-2 rounded-md hover:bg-gray-100 dark:hover:bg-gray-800 text-sm">
<span *ngIf="(uiModeService.isNimbusMode$ | async)">✨ Mode Nimbus</span>
<span *ngIf="!(uiModeService.isNimbusMode$ | async)">🔧 Mode Legacy</span>
</button>
```
### 2\) Service de gestion du mode (`ui-mode.service.ts`)
Utiliser un Signal pour une réactivité instantanée et `localStorage` pour la persistance.
```typescript
import { Injectable, signal } from '@angular/core';
@Injectable({ providedIn: 'root' })
export class UiModeService {
isNimbusMode = signal<boolean>(this.loadUIMode());
toggleUIMode(): void {
const newMode = !this.isNimbusMode();
this.isNimbusMode.set(newMode);
localStorage.setItem('obsiviewer-ui-mode', newMode ? 'nimbus' : 'legacy');
}
private loadUIMode(): boolean {
if (typeof localStorage === 'undefined') return true; // Nimbus par défaut
return localStorage.getItem('obsiviewer-ui-mode') !== 'legacy';
}
}
```
### 3\) Layout adaptatif (`app-shell-adaptive.component.ts`)
Le composant racine qui charge dynamiquement le bon layout.
```typescript
import { Component, inject } from '@angular/core';
import { UiModeService } from '@app/shared/services/ui-mode.service';
import { AppShellNimbusLayoutComponent } from '../app-shell-nimbus/app-shell-nimbus.component';
import { AppShellLegacyLayoutComponent } from '../app-shell-legacy/app-shell-legacy.component';
import { AsyncPipe } from '@angular/common';
@Component({
selector: 'app-shell-adaptive',
template: `
@if (uiModeService.isNimbusMode()) {
<app-shell-nimbus-layout></app-shell-nimbus-layout>
} @else {
<app-shell-legacy-layout></app-shell-legacy-layout>
}
`,
standalone: true,
imports: [AppShellNimbusLayoutComponent, AppShellLegacyLayoutComponent, AsyncPipe],
})
export class AppShellAdaptiveComponent {
uiModeService = inject(UiModeService);
}
```
-----
## 🎨 Spécifications Détaillées des Composants (UX & UI)
### 1\. Colonne Centrale : Recherche & Filtres (Le Cerveau)
#### **Desktop & Mobile**
- **Barre de Recherche Principale** : Large, centrée sur Desktop. Sur mobile, elle est proéminente en haut de la vue "Liste".
- **Trio de Chips de Filtres** : Juste sous la recherche, implémenter trois boutons "stateful" :
- `Tous les dossiers ▾` | `Tous les tags ▾` | `Toutes les pages ▾`
- Chaque chip affiche un **badge de comptage** (ex: `+2`) si des sélections sont actives.
- Cliquer ouvre un **Picker flottant (overlay)** :
- **UI du Picker** : Barre de recherche interne, liste scrollable, et boutons `Réinitialiser` / `Appliquer` en bas.
- **Picker Dossiers** : Affiche l'arborescence avec des chevrons `` pour déplier les sous-dossiers. Utilise des checkboxes pour la multi-sélection.
- **Picker Tags** : Liste alphabétique de tags avec des checkboxes.
- **Feedback de Recherche** : Afficher un message `N pages trouvées` avec un lien `Effacer les filtres` quand des filtres sont actifs.
### 2\. Colonne de Gauche : Navigation (La Carte)
#### **Desktop (`<app-left-sidebar.desktop.component.ts`)**
- Layout fixe et resizable.
- Structure : `Liens Rapides`, puis `Dossiers`, `Tags`.
- **Pattern Hover-Reveal** : Une icône `+` apparaît à droite d'un nom de dossier au survol pour créer un sous-dossier, gardant l'interface épurée.
- **Styling** : Autoriser les emojis dans les noms de dossiers/tags. Le dossier actif doit avoir un surlignage clair (ex: fond bleu pâle et bordure gauche bleue).
#### **Mobile (`<app-left-sidebar.mobile.component.ts`)**
- Le contenu de la sidebar est placé dans un **drawer** qui s'ouvre depuis la gauche (via un bouton "hamburger" ou un swipe depuis le bord de l'écran).
- Le drawer doit avoir un fond semi-opaque (`backdrop`) pour fermer en cliquant à l'extérieur.
### 3\. Panneau de Droite : Lecteur & Sommaire (La Page)
#### **Desktop (`<app-note-view.desktop.component.ts`)**
- Le titre de la page est large et très lisible.
- **Bouton de Sommaire (ToC) Flottant** : Un bouton circulaire avec une icône de type "liste" est fixé verticalement à droite du contenu.
- Au clic, il **déplie un panneau latéral** listant les titres H1-H6 du document.
- Cliquer sur un titre dans le sommaire scrolle la vue jusqu'à l'ancre correspondante.
- **Barre d'Actions** : Placer les actions contextuelles (Partager, Exporter, etc.) dans une barre d'outils en haut à droite du panneau.
#### **Mobile (`<app-note-view.mobile.component.ts`)**
- Le lecteur prend toute la largeur de l'écran pour une immersion maximale.
- Le **bouton de sommaire flottant** est également présent, mais en bas à droite (comme un FAB - Floating Action Button).
- Au clic, le sommaire s'ouvre en **overlay pleine page** ou dans un **panneau qui glisse depuis le bas**.
### 4\. Navigation Mobile : Bottom Bar & Gestures
- **Bottom Navigation Bar (`<app-bottom-nav.component.ts`)** :
- Fixée en bas, toujours visible sur mobile/tablette.
- Contient 3 ou 4 icônes pour basculer entre les vues principales : `Navigation (Dossiers/Tags)`, `Liste`, et `Page`. L'icône active est visuellement distincte.
- **Directive de Swipe (`swipe-nav.directive.ts`)** :
- Créer une directive Angular pour détecter les swipes gauche/droite.
- L'appliquer au conteneur principal pour permettre de naviguer entre les vues `Liste` et `Page` de manière fluide.
-----
## ⚡ Performance & Optimisations Mobiles
- **Virtual Scrolling** : Indispensable pour la colonne centrale pour afficher des milliers de notes sans impacter les performances. Utiliser le CDK de Angular.
- **Lazy Loading** : Charger les composants de layout (Nimbus/Legacy) et les vues mobiles/desktop en lazy loading.
- **Debounce** : Appliquer un debounce de 300ms sur l'input de recherche pour éviter des requêtes excessives.
- **Touch Targets** : Sur mobile, tous les éléments cliquables (boutons, items de liste) doivent avoir une taille minimale de 44x44px pour l'accessibilité.
-----
## ✅ Critères d'Acceptation
### Général
- [ ] Le toggle UI fonctionne, persiste l'état, et ne cause aucune perte de contexte.
- [ ] L'application est fluide et réactive sur tous les breakpoints, de 320px à 1920px+.
### Desktop (≥1024px)
- [ ] Le layout à 3 colonnes est fonctionnel, avec des séparateurs resizables.
- [ ] Les pickers de filtres (dossiers/tags) fonctionnent avec leur recherche interne.
- [ ] Le bouton `+` pour créer des sous-dossiers apparaît bien au survol.
- [ ] Le panneau de sommaire (ToC) se déplie depuis le bouton flottant et la navigation par ancre fonctionne.
### Tablette & Mobile (\<1024px)
- [ ] La navigation par onglets en bas de l'écran est fonctionnelle et intuitive.
- [ ] La sidebar de navigation s'ouvre et se ferme correctement en tant que drawer.
- [ ] Les gestures de swipe pour naviguer entre les vues sont fluides.
- [ ] Le sommaire s'ouvre dans un overlay ou un panneau adapté au format mobile.
- [ ] L'UI est optimisée pour le tactile (grandes zones de clic, pas de hover-dependant features).
### Accessibilité & Performance
- [ ] Score Lighthouse : Performance ≥ 90, Accessibilité ≥ 95.
- [ ] Navigation au clavier complète sur Desktop.
- [ ] ARIA-labels corrects pour tous les contrôles interactifs.

View File

@ -0,0 +1,903 @@
# 🎯 Prompt Windsurf — ObsiViewer Nimbus UI (Desktop + Mobile)
## ObsiViewer → UI/UX "Nimbus-like" (simple, dense, rapide)
**Rôle & mode :** Agis comme **Staff Frontend Engineer Angular 20 + UX designer**. Raisonnement détaillé autorisé. Tu as les pleins pouvoirs de refactor UI, d'ajout de composants, et de migration CSS vers Tailwind. Conserve la compatibilité de toutes features existantes.
**Contrainte majeure :** L'interface doit être **100% responsive** et compatible à 100% avec les modes Desktop et Mobile (téléphone et tablette). Un **bouton toggle** dans la navbar permet de basculer entre l'ancienne interface et la nouvelle sans perte d'état. Assure une expérience fluide sur tous les appareils, avec des adaptations spécifiques pour les écrans tactiles (touch targets ≥44x44px), gestures (swipe, pull-to-refresh), et breakpoints optimisés pour téléphones (xs/sm), tablettes (md), et desktops (lg/xl/2xl).
---
## Contexte rapide
* Projet : **ObsiViewer** (Angular 20 + Tailwind, Node/Express backend).
* Objectif : Refondre l'interface selon un design **Nimbus Notes / FuseBase Note**-like, en intégrant fidèlement la lecture anatomique et UX décrite ci-dessous.
* Cœurs d'usage : navigation par **dossiers**, **tags**, **recherche**, **lecture markdown** plein écran, **ToC** à droite, **tri et filtres** rapides.
* **Nouveauté** : Design adaptatif complet (Desktop/Mobile/Tablet) avec UI toggle persisté.
### Description détaillée de l'interface Nimbus (à reproduire fidèlement)
Voici une **lecture “anatomique” et UX** de linterface Web de *Nimbus Notes / FuseBase Note*, rédigée comme le ferait un lead designer qui doit la reproduire fidèlement. Cette description guide toute la refonte et doit être intégrée à 100% dans l'implémentation, en veillant à la compatibilité Desktop/Mobile/Tablet (par exemple, colonnes empilées ou onglets sur mobile, drawers tactiles sur tablette).
---
# 1) Philosophie produit (ce qui guide toute lUI)
* **Workspace-first** : tout vit dans un *espace de travail* isolé (pages, dossiers, tags, membres). On change despace, on change dunivers de contenu ce nest pas un simple filtre global. ([FuseBase][1])
* **Organisation bi-axiale** : **dossiers (hiérarchie)** + **tags (multi-catégories)**. Les dossiers structurent, les tags donnent le contexte transversal et la recherche rapide. ([FuseBase][2])
* **Recherche dabord, navigation ensuite** : la *top bar* met la recherche au centre, avec des *chips* de filtres persistants (“All folders / All tags / All pages”) qui rendent létat des filtres **visible, éditable et réinitialisable** sans quitter le flux.
* **Progressive disclosure** : menus condensés, panneaux contextuels (picker dossiers/tags, panneau doutline à droite) qui napparaissent que “on demand” pour ne jamais surcharger lécran.
* **Un contenu, plusieurs façades** : la page est éditée dans lapp interne, mais peut être **partagée** ou **publiée** dans un **Portal** externe *brandé*. Les commandes “Add to portal / Share” sont toujours visibles dans léditeur. ([FuseBase][3])
---
# 2) Layout global (3 panneaux + overlays)
## A. Barre supérieure (globale)
* **Champ de recherche** large, centré, avec **icône filtre** (entonnoir) qui ouvre les options avancées.
* Bouton **“+ Page”** (CTA positif turquoise) : création immédiate dans le contexte courant (workspace + dossier sélectionné).
* À droite, dans la *content toolbar* du document : **Ask AI**, **Add to portal**, **Share**, loupe locale, pièces jointes/annotations, **toggle plein écran**, menu kebab. (Les intitulés et la présence “Ask AI / Portals” sont aussi documentés côté guides.) ([FuseBase][4])
## B. Colonne de gauche (navigation primaire)
* **Quick Links** puis **Folders / Tags / Trash** — arborescence compacte avec triangles de disclosure.
* **Création de sous-dossier au survol** via un **+** qui apparaît à droite du dossier (pattern hover-reveal). ([FuseBase][2])
* **Sélecteur dorganisation/workspace** et **switch de thème** dans le footer du rail (menu avatar : “Light theme”, Settings, etc.). Le changement despace est aussi accessible depuis la colonne et le menu avatar. ([FuseBase][5])
* **État** : le dossier actif est surligné, le compteur de pages peut apparaître à côté des libellés (donnant un feedback rapide sur la densité).
**Traits de design**
* Icônes de dossiers colorées + emojis autorisés dans les noms (lisibilité + repères mnémotechniques).
* Densité **compacte** mais respirante (gouttière + padding régulier), contrastes élevés en dark mode.
## C. Colonne centrale (index / résultats)
* En-tête dindex : *chips* **All folders ▾**, **All tags ▾**, **All pages ▾**. Chacune ouvre un **picker flottant** (overlay) :
* **Picker dossiers** : recherche interne, sélection multi, sous-dossiers avec *chevron/*, actions **Clear / Done**, badges *+1*, *+15* reflétant le nombre de sélections.
* **Picker tags** : liste alphabétique, **checkmarks** pour les tags actifs, **Clear / Done** en bas.
* En dessous, **liste des pages** : tuiles en une ligne avec **titre**, **date**, **snippet** (extrait), **petites icônes** (ex. carte *bookmark* pour les liens sauvegardés). Le *hover* change légèrement le fond ; lélément sélectionné est **surligné** (bleu).
* **Message “Found pages: N”** + lien **Clear** lorsque des filtres sont actifs (feed-back lisible de létat de recherche).
**Subtilités dusage**
* Les *chips* de filtre restent visibles pendant la navigation (ancrage cognitif).
* Chaque picker possède sa **barre de recherche locale**, ce qui réduit la charge mentale sur de gros jeux de tags/dossiers.
* Les *chips* affichent des **badges de comptage** (+1, +2) et un **caret** pour signifier quil sagit dun *menu stateful*, pas dun simple label.
## D. Panneau de droite (lecteur/éditeur)
* **Titre de page** très lisible, méta-ligne en dessous (ex. *Add tags*), mini-icônes de statut.
* **Contenu riche** : titres, listes, *inline code*, *code fences*, callouts, objets embarqués, cartes “**Bookmark**” (prévisualisation dURL avec titre/description/vignette). ([FuseBase][6])
* **Toolbar du document** (droite) :
* **Ask AI** (génération, résumé, etc.) ; **Add to portal** (publier la page dans une arborescence publique/privée) ; **Share** (lien partagé, droits). ([FuseBase][3])
* Loupe/“find in page”, attachements, rappel/notification si activés, **plein écran** avec raccourci (tooltip).
* **Panneau latéral contextuel (outline)** : petit bouton *hamburger* rond “dans la page” (à mi-hauteur, côté droit) qui **déplie un rail doutline** listant les headings H1H6 ; clic = **scroll-to**. (Très utile sur documents longs, *progressive disclosure*).
**Édition & Portals (workflow)**
* Lédition se fait **directement** côté web, et lon peut **pousser** vers un *Portal* sans passer par un autre back-office : “Add to portal” + *drag & drop* vers la structure du Portal (depuis le rail). ([FuseBase][3])
## E. Overlays & états transitoires
* **Pickers** (Folders/Tags) : overlays centrés au-dessus de la colonne des résultats, avec **Clear/Done** persistants en pied.
* **Dark / Light** : toggles dans le menu avatar ; la **typographie/balances de gris** sont recalibrées (mode light très clair, mode dark très contrasté) pour garder le même *information scent*.
* **Notifications/Tooltips** : discrets, ancrés aux contrôles (ex. plein écran).
---
# 3) Micro-interactions & patterns récurrents
* **Hover-reveal** : le “+” pour créer un sous-dossier napparaît quau survol → garde larborescence propre. ([FuseBase][2])
* **Pills / Chips** avec **caret** + **badge** = *stateful filter* (on comprend dun coup dœil ce qui est filtré).
* **Sélection persistante** dans la liste : lélément actif garde un **fond** et une **bordure** turquoise ; on ne “perd” pas la page lue.
* **Clear partout** : dans les pickers et au niveau global la stratégie de *reset rapide* est omniprésente (réduction du coût dexploration).
* **Hiérarchie visuelle stricte** : H1H3 très différenciés, marges généreuses, *line-height* confortable (lecture longue).
---
# 4) Contenus & types spéciaux
* **Bookmarks** : carte enrichie (titre + description + vignette) → meilleure *scanability* des liens sauvegardés que du simple texte. ([FuseBase][6])
* **Tables/Databases** : vues avec tri, filtres, commentaires cellule, panneau de calcul (présents dans lécosystème guides). ([FuseBase][4])
* **Web Clipper** : amène des pages propres (sans pubs), cohérent avec la carte Bookmark ; logique de capture → enrichissement → partage. ([FuseBase][7])
---
# 5) Accessibilité & lisibilité
* **Contrastes sûrs** (notamment en dark), tailles de cible suffisantes sur la top bar et les chips.
* **Iconographie descriptive** (dossier, tag, favoris, web card…) + emojis pour ancrage visuel rapide.
* **Réduction du *cognitive load*** : les options rarement utilisées sont “cachées” (kebab, hover-reveal), les actions courantes sont **toujours** visibles (Search, +Page, filtres).
---
# 6) Ce que lUX “raconte” (le mode demploi implicite)
1. **Trouver** : commencez par *Search* et affinez avec *All folders / All tags*.
2. **Parcourir** : si vous êtes “dans” un dossier, lindex au centre sert de *tableau de bord* (dates + snippets).
3. **Éditer / Enrichir** : dans le panneau de droite, vous rédigez, taggez, joignez, bookmarquez.
4. **Diffuser** : *Share* pour du partage direct, **Add to portal** pour publier dans un espace externe gouverné (droits, branding). ([FuseBase][8])
---
# 7) Détails visibles dans vos captures (à reproduire à lidentique)
* **Top bar** : champ de recherche + icône filtre + **+ Page** (CTA turquoise).
* **Trio de chips** : “All folders ▾” (multi-sélection hiérarchique), “All tags ▾” (liste à coches), “All pages ▾”.
* **Liste** : ligne compacte, *hover*, *selected state* bleu, **date** en gris, **snippet** tronqué, petite icône (ex. “shopping cart” pour bookmark e-commerce).
* **Panneau doutline** (badge hamburger circulaire flottant à droite du contenu) → rail doutline repliable.
* **Menu avatar (footer gauche)** : **Light theme**, Settings, Upgrade, logout, etc.
* **Dark/Light** : la *skin* claire conserve larchitecture et les espacements, en ne changeant que la palette et les ombres.
---
## TL;DR — Nimbus en 8 principes à retenir (pour inspirer un redesign)
1. **Trois panneaux** stables (nav / index / contenu) + **overlays** transitoires.
2. **Filtres persistants** sous forme de **chips** toujours visibles.
3. **Pickers** riches (recherche locale, checkmarks, Clear/Done).
4. **Outline contextuel** à droite, déclenché **dans** la page.
5. **Action de création** unique, toujours au même endroit (**+ Page**).
6. **Workspaces** strictement séparés ; **Portals** pour lexterne. ([FuseBase][1])
7. **Bi-axe dossiers/tags** (structure + sens transversal). ([FuseBase][2])
8. **Share/Add to portal** omniprésents : écrire → publier est un **continuum**. ([FuseBase][8])
Si tu veux, je peux te livrer juste après un *spec UI* prêt à coder (grid, tailles, tokens couleur, comportements exacts des pickers) ou un **prompt Windsurf** pour cloner ces patterns dans ObsiViewer.
[1]: https://thefusebase.com/guides/basics/workspaces/?utm_source=chatgpt.com "Workspaces"
[2]: https://thefusebase.com/guides/basics/folders-and-tags/?utm_source=chatgpt.com "Folders and Tags"
[3]: https://thefusebase.com/guides/client-portal/how-to-manage-your-portal-from-the-web-version/?utm_source=chatgpt.com "How To Manage Your Portal From The Web Version"
[4]: https://thefusebase.com/guides/?utm_source=chatgpt.com "Guides Archive"
[5]: https://nimbusweb.me/fr/guides/getting-started/how-to-navigate/?utm_source=chatgpt.com "How to navigate"
[6]: https://nimbusweb.me/guides/basics/bookmarks/?utm_source=chatgpt.com "Bookmarks"
[7]: https://thefusebase.com/guides/web-clipper/nimbus-clipper-for-google-chrome/?utm_source=chatgpt.com "Nimbus Clipper for Google Chrome"
[8]: https://thefusebase.com/guides/embedding-sharing/shared-folders-and-pages/?utm_source=chatgpt.com "Shared folders and pages"
---
## 🎯 Objectif final (résumé)
### Desktop (≥1024px)
Refondre l'interface ObsiViewer en **3 colonnes** respectant fidèlement la description Nimbus :
1. **Sidebar gauche** (Quick Links, Dossiers arborescents, Tags) — Redimensionnable.
2. **Colonne centrale** Liste des pages (recherche, filtres dossiers/tags, tris, résultats virtualisés).
3. **Vue de page** à droite (lecture markdown, barre d'actions, **panneau sommaire/ToC** docké à l'extrême droite).
Le tout **compact, performant, thème clair/sombre**, navigation au clavier, états persistés localement.
### Mobile/Tablet (<1024px)
Une navigation **par onglets/drawer** intelligente, adaptée à la philosophie Nimbus (progressive disclosure, chips persistants, overlays tactiles) :
- **Tab 1 : Sidebar** (dossiers, tags, recherche) — Panneau full-width ou drawer collapsible.
- **Tab 2 : Liste** (résultats de recherche) — Full-width scrollable.
- **Tab 3 : Page** (markdown) — Full-width avec ToC inline collapsible ou drawer.
**Gestures** : Swipe horizontal pour navigation onglets, pull-to-refresh, tap = open item. Assure que les chips de filtres et pickers sont optimisés pour touch (tailles augmentées, overlays pleine largeur sur mobile).
---
## 📋 Architecture Feature Flag & Toggle
### 1) Toggle UI dans la NavBar
Ajouter un **bouton toggle** dans `src/app/layout/app-navbar/app-navbar.component.ts` :
```html
<!-- app-navbar.component.html (snippet) -->
<div class="flex items-center gap-2">
<!-- Autres boutons -->
<button
(click)="toggleUIMode()"
[attr.aria-label]="'Toggle ' + (isNimbusMode$ | async ? 'legacy' : 'nimbus') + ' UI'"
class="p-2 rounded hover:bg-gray-100 dark:hover:bg-gray-800">
<span *ngIf="(isNimbusMode$ | async)">✨ Nimbus</span>
<span *ngIf="!(isNimbusMode$ | async)">🔧 Legacy</span>
</button>
</div>
```
### 2) Service de gestion du mode UI
Créer `src/app/shared/services/ui-mode.service.ts` :
```typescript
import { Injectable, signal } from '@angular/core';
@Injectable({ providedIn: 'root' })
export class UiModeService {
// Signal pour réactivité fine-grained
isNimbusMode = signal<boolean>(this.loadUIMode());
constructor() {}
toggleUIMode() {
const newMode = !this.isNimbusMode();
this.isNimbusMode.set(newMode);
localStorage.setItem('obsiviewer-ui-mode', newMode ? 'nimbus' : 'legacy');
}
private loadUIMode(): boolean {
if (typeof localStorage === 'undefined') return false;
const saved = localStorage.getItem('obsiviewer-ui-mode');
return saved ? saved === 'nimbus' : true; // Nimbus par défaut
}
}
```
### 3) Layout wrapper avec feature flag
Créer `src/app/layout/app-shell-adaptive/app-shell-adaptive.component.ts` :
```typescript
import { Component, inject } from '@angular/core';
import { UiModeService } from '@app/shared/services/ui-mode.service';
import { AppShellNimbusLayoutComponent } from '../app-shell-nimbus/app-shell-nimbus.component';
import { AppShellLegacyLayoutComponent } from '../app-shell-legacy/app-shell-legacy.component';
@Component({
selector: 'app-shell-adaptive',
template: `
@if (uiMode.isNimbusMode()) {
<app-shell-nimbus-layout></app-shell-nimbus-layout>
} @else {
<app-shell-legacy-layout></app-shell-legacy-layout>
}
`,
standalone: true,
imports: [AppShellNimbusLayoutComponent, AppShellLegacyLayoutComponent],
})
export class AppShellAdaptiveComponent {
uiMode = inject(UiModeService);
}
```
---
## 🎨 Responsive Design Strategy
### Breakpoints Tailwind (standard)
```typescript
// tailwind.config.js
module.exports = {
theme: {
screens: {
'xs': '320px', // iPhone SE
'sm': '640px', // Petites tablettes
'md': '768px', // iPad, tablettes
'lg': '1024px', // Desktop compact
'xl': '1280px', // Desktop standard
'2xl': '1536px', // Larges écrans
},
},
};
```
### Mobile First Approach
**Développer pour mobile d'abord, puis enrichir pour desktop.** Assure que tous les éléments Nimbus (chips, pickers, outline) sont tactiles et responsifs : par exemple, chips scrollables horizontalement sur mobile, pickers en modales pleine largeur sur téléphone/tablette.
---
## 📱 Layouts Responsifs
### Desktop Layout (≥1024px)
```
┌─────────────────────────────────────────────────────────┐
│ NAVBAR (Dark, fixed, h-14) │
├────────────────┬──────────────────┬──────────────────────┤
│ │ │ │
│ SIDEBAR │ RESULT LIST │ NOTE VIEW + TOC │
│ (240-440px) │ (virtualized) │ (Resizable) │
│ Resizable │ │ │
│ │ │ │
│ - Quick │ - Search bar │ - Markdown │
│ Links │ - Filters │ - ToC drawer │
│ - Folders │ - Items (80px) │ - Actions bar │
│ - Tags │ - Pagination │ │
│ │ │ │
└────────────────┴──────────────────┴──────────────────────┘
```
### Tablet Layout (768px ≤ width < 1024px)
```
┌──────────────────────────────────────┐
│ NAVBAR + Toggle (fixed, h-14) │
├──────────────────────────────────────┤
│ TAB NAVIGATION (fixed, bottom) │
│ [Sidebar] [List] [Page] [ToC] │
├──────────────────────────────────────┤
│ │
│ ACTIVE TAB CONTENT (scrollable) │
│ - Drawer si besoin │
│ - Full-width panels │
│ │
└──────────────────────────────────────┘
```
### Mobile Layout (<768px)
```
┌──────────────────────────────────┐
│ NAVBAR (compact, h-12) │
│ [Menu] [Search] [Toggle] │
├──────────────────────────────────┤
│ │
│ TAB/DRAWER NAVIGATION │
│ [≡] [🔍] [📄] [📋] │
│ │
│ CONTENT AREA (Full-width) │
│ - Drawer sidebar (80vw left) │
│ - Swipeable list (list tab) │
│ - Markdown full-screen (page) │
│ - Inline ToC (toggle button) │
│ │
├──────────────────────────────────┤
│ Bottom Navigation (sticky) │
│ Tab buttons (4 icônes) │
└──────────────────────────────────┘
```
---
## 🎬 Composants Nimbus Responsifs
### Desktop/Mobile Variants
Chaque composant doit avoir des **variants responsifs** intégrant les patterns Nimbus (hover-reveal sur desktop, tap-reveal sur mobile ; chips avec badges tactiles) :
```
app-left-sidebar/
├── app-left-sidebar.component.ts # Logique partagée
├── app-left-sidebar.desktop.component.ts # ≥1024px (fixed, resizable)
└── app-left-sidebar.mobile.component.ts # <1024px (drawer)
app-center-list/
├── app-center-list.component.ts
├── app-center-list.desktop.component.ts # ≥1024px (2 colonnes)
└── app-center-list.mobile.component.ts # <1024px (full-width)
app-note-view/
├── app-note-view.component.ts
├── app-note-view.desktop.component.ts # ≥1024px (3 colonnes + ToC)
└── app-note-view.mobile.component.ts # <1024px (full-width + ToC inline)
app-toc-drawer/
├── app-toc-drawer.component.ts
├── app-toc-drawer.desktop.component.ts # ≥1024px (Fixed right)
└── app-toc-drawer.mobile.component.ts # <1024px (Collapsible, inline)
```
### Détection et Injection
```typescript
// app-left-sidebar.component.ts
import { Component, inject } from '@angular/core';
import { BreakpointObserver, Breakpoints } from '@angular/cdk/layout';
@Component({
selector: 'app-left-sidebar',
standalone: true,
template: `
@if (isDesktop$ | async) {
<ng-container *ngComponentOutlet="DesktopSidebarComponent"></ng-container>
} @else {
<ng-container *ngComponentOutlet="MobileSidebarDrawerComponent"></ng-container>
}
`,
})
export class AppLeftSidebarComponent {
private breakpoint = inject(BreakpointObserver);
isDesktop$ = this.breakpoint.observe(Breakpoints.Large).pipe(
map(result => result.matches)
);
}
```
---
## 📱 Navigation Mobile Avancée
### Tab/Drawer Navigation
```typescript
// src/shared/services/mobile-nav.service.ts
@Injectable({ providedIn: 'root' })
export class MobileNavService {
activeTab = signal<'sidebar' | 'list' | 'page' | 'toc'>('list');
setTab(tab: 'sidebar' | 'list' | 'page' | 'toc') {
this.activeTab.set(tab);
// Persist if needed
}
}
// Usage in component
<app-bottom-nav [activeTab]="mobileNav.activeTab()"
(tabChange)="mobileNav.setTab($event)">
</app-bottom-nav>
```
### Swipe Navigation (Gestures)
```typescript
// Directive pour détection de swipe
import { Directive, Output, EventEmitter, HostListener } from '@angular/core';
@Directive({
selector: '[appSwipeNav]',
standalone: true,
})
export class SwipeNavDirective {
@Output() swipeLeft = new EventEmitter<void>();
@Output() swipeRight = new EventEmitter<void>();
private startX = 0;
@HostListener('touchstart', ['$event'])
onTouchStart(e: TouchEvent) {
this.startX = e.touches[0].clientX;
}
@HostListener('touchend', ['$event'])
onTouchEnd(e: TouchEvent) {
const endX = e.changedTouches[0].clientX;
const diff = this.startX - endX;
if (Math.abs(diff) > 50) { // Seuil minimum
if (diff > 0) this.swipeLeft.emit();
else this.swipeRight.emit();
}
}
}
```
---
## 🎨 Composants Spécifiques (Mobile-First)
### 1) Bottom Navigation (Mobile)
```html
<!-- app-bottom-nav.component.html -->
<nav class="fixed bottom-0 left-0 right-0 bg-white dark:bg-gray-900 border-t
border-gray-200 dark:border-gray-800 h-16 flex justify-around md:hidden">
<button *ngFor="let tab of tabs"
(click)="selectTab(tab.id)"
[class.active]="activeTab === tab.id"
class="flex-1 flex flex-col items-center justify-center gap-1
text-xs hover:bg-gray-50 dark:hover:bg-gray-800">
<span class="text-lg">{{ tab.icon }}</span>
<span>{{ tab.label }}</span>
</button>
</nav>
```
### 2) Drawer Sidebar (Mobile)
```html
<!-- app-left-sidebar.mobile.component.html -->
<aside class="fixed left-0 top-0 bottom-0 w-80vw max-w-xs
bg-white dark:bg-gray-900 shadow-lg z-50
transform transition-transform duration-300"
[class.-translate-x-full]="!isOpen">
<!-- Contenu sidebar -->
<button (click)="close()" class="absolute top-4 right-4"></button>
</aside>
<!-- Backdrop -->
<div *ngIf="isOpen"
(click)="close()"
class="fixed inset-0 bg-black/50 z-40 md:hidden"></div>
```
### 3) Search Bar Compact (Mobile)
```html
<!-- app-search-bar.mobile.component.html -->
<div class="sticky top-0 bg-white dark:bg-gray-900 p-2 shadow-sm z-10">
<div class="flex gap-2">
<!-- Menu toggle -->
<button (click)="toggleSidebar()"
class="p-2 rounded hover:bg-gray-100">☰</button>
<!-- Search input (full-width on mobile) -->
<input type="text"
placeholder="Search..."
class="flex-1 px-3 py-2 rounded border dark:border-gray-700">
<!-- Filters button (mobile: popover instead of dropdown) -->
<button (click)="openFilters()"
class="p-2 rounded hover:bg-gray-100">⚙️</button>
</div>
<!-- Active badges (scrollable horizontally) -->
<div class="flex gap-1 mt-2 overflow-x-auto">
<span *ngFor="let badge of activeBadges"
class="badge badge-sm">
{{ badge }} ✕
</span>
</div>
</div>
```
### 4) Result List Item (Mobile-Optimized)
```html
<!-- app-result-list-item.component.html -->
<div class="p-3 border-b hover:bg-gray-50 dark:hover:bg-gray-800 cursor-pointer">
<!-- Title -->
<h3 class="font-semibold text-sm sm:text-base truncate">
{{ item.title }}
</h3>
<!-- Date + Tags (stacked on mobile) -->
<div class="flex flex-col sm:flex-row sm:items-center gap-1 mt-1 text-xs text-gray-600">
<span>{{ item.modified | date:'short' }}</span>
<div class="flex gap-1 flex-wrap">
<span *ngFor="let tag of item.tags"
class="badge badge-sm">{{ tag }}</span>
</div>
</div>
<!-- Excerpt (truncated) -->
<p class="mt-2 text-xs text-gray-600 line-clamp-2">
{{ item.excerpt }}
</p>
</div>
```
### 5) Markdown Viewer (Mobile-Responsive)
```html
<!-- app-markdown-viewer.component.html -->
<article class="prose dark:prose-invert max-w-none
prose-sm sm:prose-base
prose-img:max-w-full prose-img:h-auto
px-3 sm:px-6 py-4 sm:py-8">
<!-- Markdown content -->
<div [innerHTML]="markdownHTML"></div>
<!-- ToC (mobile: inline toggle) -->
<button *ngIf="headings.length > 0"
(click)="showToC = !showToC"
class="lg:hidden fixed bottom-20 right-4 p-3 rounded-full bg-blue-500 text-white shadow-lg">
📋
</button>
<nav *ngIf="showToC" class="lg:hidden fixed inset-0 bg-white dark:bg-gray-900
z-40 overflow-y-auto p-4">
<!-- ToC content -->
</nav>
</article>
```
### 6) ToC Drawer (Desktop Fixed, Mobile Inline)
```typescript
// app-toc-drawer.component.ts
@Component({
selector: 'app-toc-drawer',
template: `
<!-- Desktop: Fixed right panel (≥1024px) -->
<aside class="hidden lg:flex fixed right-0 top-14 bottom-0 w-64
bg-gray-50 dark:bg-gray-800 border-l
border-gray-200 dark:border-gray-700
flex-col overflow-y-auto">
<app-toc-content [headings]="headings"></app-toc-content>
</aside>
<!-- Mobile: Collapsible inline (< 1024px) -->
<div *ngIf="(isMobile$ | async)"
[@slideDown]="showTocMobile ? 'in' : 'out'"
class="bg-gray-50 dark:bg-gray-800 border-t p-3 max-h-96 overflow-y-auto">
<app-toc-content [headings]="headings"></app-toc-content>
</div>
`,
animations: [
trigger('slideDown', [
state('in', style({ height: '*' })),
state('out', style({ height: '0px' })),
transition('in <=> out', animate('200ms ease-in-out')),
]),
],
standalone: true,
})
export class AppTocDrawerComponent {
@Input() headings: Heading[] = [];
showTocMobile = false;
isMobile$ = this.breakpoint.observe('(max-width: 1023px)').pipe(
map(r => r.matches)
);
}
```
---
## 🎯 Livrables Attendus
### Code
1. **Toggle UI** : `UiModeService`, bouton navbar, `AppShellAdaptiveComponent`
2. **Responsive Wrappers** : Variants pour chaque composant (Desktop/Mobile), intégrant les patterns Nimbus
3. **Mobile Components** : Bottom nav, drawer sidebar, inline ToC, mobile search
4. **Gesture Handling** : Swipe navigation directive, touch-friendly interactions
5. **Breakpoint Utilities** : Service CDK layout, reactive signals
### Styling
1. **Tailwind Config** : Breakpoints personnalisés, tokens clair/sombre
2. **Mobile-First CSS** : Base mobile, enrichissements desktop via `md:`, `lg:`
3. **Touch-Friendly** : Boutons ≥44x44px, padding adéquat, hover states remplacés par tap sur mobile
### Documentation
1. **README_UI.md** : Schémas responsive, breakpoints, guide toggle, intégration Nimbus
2. **MOBILE_GUIDE.md** : Navigation gestures, bottom nav flow, drawer patterns
3. **RESPONSIVE_CHECKLIST.md** : Tests par breakpoint, checklist A11y mobile
### Tests
1. **E2E** : Toggle persistence, layout switch, gesture navigation
2. **Visual Regression** : Screenshots desktop/tablet/mobile
3. **Accessibility** : Touch targets, ARIA labels, keyboard nav (Tab key)
---
## ⚡ Performance & Mobile Optimizations
### Critical Optimizations
- **Lazy-load images** : `loading="lazy"`, responsive `srcset`
- **Virtual scroll** : CDK virtual scroll adapté mobile (item height ≈ 7080px)
- **Debounce search** : 300ms sur mobile, 150ms sur desktop
- **Avoid layout shift** : Aspect ratios, skeleton loaders
- **Network awareness** : `navigator.connection.effectiveType` pour adapt qualité
- **Battery saver** : Réduire animations, throttle updates en mode saver
### Lighthouse Mobile Targets
- Performance ≥ 85
- Accessibility ≥ 95
- Best Practices ≥ 90
---
## 🎮 Raccourcis Clavier & Gestures
### Desktop
- `Ctrl/Cmd + K` : Palette commandes
- `Ctrl/Cmd + F` : Focus recherche
- `[` `]` : Replier/ouvrir ToC
- `Alt + ←/→` : Navigation historique
### Mobile/Tablet
- **Tap** : Ouvrir note/item
- **Swipe left/right** : Changer onglet (list → page → sidebar)
- **Long-press** : Menu contextuel (favoris, open in new tab)
- **Pull-to-refresh** : Rafraîchir liste (optionnel)
- **Double-tap** : Zoom ToC (mobile)
---
## 📋 Critères d'Acceptation
### Desktop (≥1024px)
- [x] Layout 3 colonnes (sidebar fixe/resizable, liste, page+ToC), fidèle à Nimbus
- [x] Changement dossier/tag/tri reflété en URL
- [x] 1000+ items fluide (60fps virtual scroll)
- [x] ToC synchronisé + repliable
- [x] Tous les flux clavier-seuls possibles
### Tablet (7681023px)
- [x] Navigation par onglets (Sidebar / List / Page)
- [x] Drawer sidebar (80vw, swipeable)
- [x] Bottom navigation sticky (4 icônes)
- [x] Contenu full-width par onglet
- [x] ToC inline collapsible
### Mobile (<768px)
- [x] Drawer sidebar (80vw max)
- [x] Bottom nav (4 onglets)
- [x] Search bar compact (menu + search + filters)
- [x] List items optimisés (titre + date + excerpt)
- [x] Markdown full-screen
- [x] ToC overlay ou inline toggle
- [x] Touch targets ≥ 44x44px
### Feature Flag
- [x] Toggle UI visible dans navbar
- [x] État persisté (localStorage)
- [x] Pas de perte d'état lors du switch
- [x] Legacy UI reste intacte
### Accessibility
- [x] WCAG 2.1 AA sur tous les breakpoints
- [x] Keyboard navigation complète (Tab, Arrow, Enter)
- [x] ARIA labels pour navigation tactile
- [x] Focus visible partout
- [x] Zoom ≤ 200% sans horizontal scroll
### Performance
- [x] TTI < 2.5s cold start
- [x] Scroll 60fps sur 1000+ items
- [x] Lighthouse Mobile ≥ 85 perf, ≥ 95 a11y
- [x] ImageOptimizations (lazy, srcset, format next-gen)
---
## 🗂️ Arborescence Fichiers
```
src/app/
├── layout/
│ ├── app-shell-adaptive/
│ │ └── app-shell-adaptive.component.ts # Feature flag wrapper
│ ├── app-shell-nimbus/
│ │ ├── app-shell-nimbus.component.ts # 3 colonnes (desktop)
│ │ ├── app-shell-nimbus.desktop.component.ts
│ │ └── app-shell-nimbus.mobile.component.ts
│ └── app-navbar/
│ ├── app-navbar.component.ts
│ └── [Bouton toggle UI intégré]
├── features/
│ ├── sidebar/
│ │ ├── app-left-sidebar.component.ts
│ │ ├── app-left-sidebar.desktop.component.ts
│ │ └── app-left-sidebar.mobile.component.ts
│ │
│ ├── search-bar/
│ │ ├── app-search-bar.component.ts
│ │ ├── app-search-bar.desktop.component.ts
│ │ └── app-search-bar.mobile.component.ts
│ │
│ ├── result-list/
│ │ ├── app-result-list.component.ts
│ │ ├── app-result-list.desktop.component.ts
│ │ ├── app-result-list.mobile.component.ts
│ │ └── app-result-list-item.component.ts
│ │
│ ├── note-view/
│ │ ├── app-note-view.component.ts
│ │ ├── app-note-view.desktop.component.ts
│ │ └── app-note-view.mobile.component.ts
│ │
│ ├── toc-drawer/
│ │ ├── app-toc-drawer.component.ts
│ │ └── app-toc-content.component.ts
│ │
│ └── bottom-nav/ [NEW]
│ ├── app-bottom-nav.component.ts
│ └── app-bottom-nav.component.html
├── shared/
│ ├── services/
│ │ ├── ui-mode.service.ts # [NEW] Toggle management
│ │ ├── mobile-nav.service.ts # [NEW] Tab/drawer state
│ │ └── breakpoint.service.ts # [NEW] Responsive helper
│ │
│ ├── directives/
│ │ └── swipe-nav.directive.ts # [NEW] Gesture detection
│ │
│ └── components/
│ └── resizable-handle/
└── styles/
├── tokens.css # Tailwind tokens
├── responsive.css # Breakpoint utilities
└── mobile.css # Mobile-specific (touches, etc.)
```
---
## 📅 Plan d'Implémentation (ordre conseillé)
1. **Feature Flag Infrastructure** (1-2j)
- `UiModeService` + localStorage persistence
- `AppShellAdaptiveComponent` wrapper
- Toggle button dans navbar
2. **Responsive Shell & Breakpoints** (2-3j)
- Desktop layout 3 colonnes (>=1024px)
- Tailwind breakpoints & tokens
- Resizable sidebar logic
3. **Mobile Navigation & Bottom Nav** (2-3j)
- `BottomNavComponent` (4 onglets)
- `MobileNavService` (state management)
- Tab/drawer routing
4. **Mobile Sidebar Drawer** (1-2j)
- Drawer animé (translate, backdrop)
- Swipe dismiss directive
- Z-index management
5. **Responsive Components** (3-4j)
- Search bar variants (desktop/mobile)
- Result list item responsive
- Markdown viewer mobile optimizations
6. **ToC Drawer Adaptive** (1-2j)
- Fixed right panel (desktop)
- Inline toggle (mobile)
- Animations smooth
7. **Gestures & Touch** (1-2j)
- Swipe nav directive
- Long-press menu
- Pull-to-refresh (optionnel)
8. **Accessibility & Testing** (2-3j)
- WCAG 2.1 AA audit
- Keyboard nav (Tab, Arrow)
- E2E tests (toggle, breakpoints, gestures)
- Visual regression (3 breakpoints)
**Total estimé** : 1321 jours (équipe 1 FE engineer)
---
## 🚀 Scripts NPM
```bash
# Dev complet (Nimbus activé par défaut)
npm run dev
# Build production
npm run build
# Tests responsifs (plusieurs breakpoints)
npm run test:responsive
# Lighthouse audit mobile
npm run audit:lighthouse:mobile
# Feature flag (override)
NIMBUS_UI=false npm run dev # Force legacy UI
```
---
## ✅ Checklist Livraison
- [ ] Toggle UI visible, fonctionnel, persisté
- [ ] Desktop (≥1024px) : 3 colonnes, interactions fluides
- [ ] Tablet (7681023px) : Onglets + drawer, full-width contenu
- [ ] Mobile (<768px) : Bottom nav, drawer, touch-friendly
- [ ] Tous les flux clavier-seuls réalisables
- [ ] Lighthouse mobile ≥ 85 perf, ≥ 95 a11y
- [ ] Virtual scroll 60fps sur 1000+ items
- [ ] Tests E2E (toggle, breakpoints, gestures)
- [ ] Documentation complète (README_UI.md, MOBILE_GUIDE.md, RESPONSIVE_CHECKLIST.md)
- [ ] Zéro régression : legacy UI inchangée, Wikilinks, bookmarks, graph intacts
- [ ] Screenshots before/after 3 breakpoints
- [ ] Fidélité 100% à la description Nimbus (chips, pickers, outline, etc.)
---
## 📖 Documentation à Produire
1. **README_UI.md** : Overview, architecture, screenshots 3 breakpoints
2. **MOBILE_GUIDE.md** : Navigation onglets, gestures, drawer patterns
3. **RESPONSIVE_CHECKLIST.md** : Tests par breakpoint, device testing
4. **DEPLOYMENT.md** : Feature flag pour bascule progressive
5. **ARCHITECTURE_DIAGRAM.md** : Schémas adaptatifs (Mermaid)
---
## 💡 Notes Importantes
- **Mobile First** : Développer pour mobile en premier, puis enrichir desktop.
- **Persistent State** : Le toggle UI et les filtres actifs doivent persister via localStorage (sans browser storage, utiliser sessionStorage ou service state).
- **Zero Regression** : L'ancienne interface reste intacte et fonctionnelle.
- **Performance** : Virtual scroll adapté mobile (40+ items à l'écran), lazy-load images.
- **Accessibility** : 44x44px touch targets minimum, ARIA labels complets, keyboard nav.
- **Testing** : Visual regression sur breakpoints clés (375px / 768px / 1440px).
- **Intégration Nimbus** : Tous les éléments de la description (philosophie, layouts, micro-interactions) doivent être reproduits fidèlement, avec adaptations responsives pour mobile/tablette (ex. hover-reveal → tap-reveal).
---
**Exécute maintenant ce plan** : crée les composants, adapte les routes/états, ajoute les styles Tailwind responsifs, branche la recherche et livre le MR conforme aux critères ci-dessus avec toggle UI et compatibilité 100% Desktop/Mobile.

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,151 @@
Voici le **prompt Windsurf révisé**, enrichi et aligné avec la **lecture anatomique UX de Nimbus Notes / FuseBase**, tout en maintenant la **compatibilité 100 % Desktop + Mobile (téléphone + tablette)** et en intégrant fidèlement les **8 principes Nimbus** :
---
# 🎯 Prompt Windsurf — ObsiViewer Nimbus UI (Desktop + Mobile)
## ObsiViewer → UI/UX “Nimbus-like” (simple, dense, rapide)
**Rôle & mode** : Agis comme **Staff Frontend Engineer Angular 20 + UX Designer**. Tu as les pleins pouvoirs pour refactoriser lUI, ajouter des composants, migrer vers Tailwind, et réorganiser larchitecture. **Toutes les fonctionnalités existantes doivent être conservées** (wikilinks, graph, bookmarks, etc.).
**Contrainte majeure** : Linterface doit être **100 % responsive** (Desktop ≥1024px, Tablet 7681023px, Mobile <768px). Un **bouton toggle UI** dans la navbar permet de basculer entre lancienne interface et la nouvelle **sans perte détat**.
---
## 🧠 Philosophie Nimbus à reproduire (8 piliers)
1. **Workspace-first** : chaque espace est un univers isolé. Le sélecteur despace doit être visible dans le footer du rail gauche.
2. **Bi-axe organisationnel** : navigation par **dossiers (hiérarchie)** + **tags (multi-catégorisation)**.
3. **Recherche dabord** : champ central + **chips de filtres persistants** (“All folders ▾”, “All tags ▾”, “All pages ▾”) avec badges de comptage.
4. **Progressive disclosure** : menus hover-reveal, overlays contextuels, panneau doutline flottant activé *dans* la page.
5. **Un contenu, plusieurs façades** : chaque note peut être **partagée** ou **publiée dans un Portal** via des boutons toujours visibles (`Share`, `Add to portal`).
6. **CTA unique** : un seul bouton **+ Page** (turquoise) en haut, centré ou à droite selon le breakpoint.
7. **Lisibilité & densité** : typographie hiérarchisée, espacements respirants, contrastes élevés en dark mode.
8. **Feedback immédiat** : états visuels clairs (sélection, filtres actifs, compteurs), boutons `Clear` omniprésents.
---
## 🎯 Objectif final (résumé)
### Desktop (≥1024px)
**Layout 3 colonnes** :
1. **Sidebar gauche** : Quick Links, arborescence dossiers/tags, création hover-reveal (+), sélecteur workspace dans le footer.
2. **Colonne centrale** : barre de recherche + **trio de chips filtrables** → liste virtualisée de pages (titre, date, snippet, icônes bookmark).
3. **Panneau droit** : vue markdown + **barre dactions contextuelles** (`Ask AI`, `Add to portal`, `Share`, plein écran) + **outline flottant** (hamburger rond à droite du contenu).
### Mobile/Tablet (<1024px)
**Navigation par onglets/drawer** :
- **Tab 1 : Sidebar** → drawer ou full-width (dossiers, tags, recherche, sélecteur workspace).
- **Tab 2 : Liste** → full-width, chips de filtres scrollables, items optimisés (titre + date + tags + excerpt).
- **Tab 3 : Page** → vue markdown plein écran, **ToC inline toggle** (bouton flottant), barre dactions compacte.
- **Gestures** : swipe horizontal entre onglets, long-press = menu contextuel, pull-to-refresh (optionnel).
---
## 🔧 Architecture Feature Flag & Toggle
Identique au prompt initial :
- `UiModeService` avec localStorage
- `AppShellAdaptiveComponent`
- Bouton toggle dans la navbar
✅ **Garantir la persistance des filtres, sélection active, workspace, et thème lors du toggle.**
---
## 📱 Composants Nimbus Responsifs (ajouts clés)
### 1. **Search & Filter Bar**
- **Desktop** : champ large centré + icône filtre + **+ Page** (turquoise)
- **Mobile** : [☰] + champ + [⚙️] → chips de filtres scrollables horizontalement sous la barre
### 2. **Filter Chips**
- Format : `All folders ▾ (+2)`, `All tags ▾ (+5)`
- Clic → **overlay picker** :
- **Folders** : arbo hiérarchique, recherche interne, multi-sélection, Clear/Done
- **Tags** : liste à coches, recherche locale, Clear/Done
### 3. **Sidebar**
- **Desktop** : rail fixe, hover-reveal “+” pour sous-dossier, icônes colorées, emojis supportés
- **Mobile** : drawer animé (80vw), accessible via [☰] ou swipe
### 4. **Result List Item**
- Compact mais lisible
- Icône bookmark si lien externe (carte enrichie)
- État sélectionné : fond + bordure turquoise
### 5. **Note View Toolbar**
- **Desktop** : `Ask AI` | `Add to portal` | `Share` | 🔍 | 📎 | 🖥️ | ⋮
- **Mobile** : icônes uniquement, en haut ou en bottom sheet
### 6. **Outline / ToC**
- **Desktop** : rail fixe à droite (≥1024px)
- **Mobile** : bouton flottant 📋 → overlay plein écran ou panneau repliable en haut
### 7. **Workspace Selector**
- Dans le **footer du rail gauche** (Desktop) ou dans le **menu avatar** (Mobile)
- Options : changement despace, thème (Light/Dark), settings, logout
---
## 🎨 Responsive Strategy
- **Mobile-first** : base mobile → enrichissements `md:`, `lg:`
- **Breakpoints Tailwind** :
- `xs: 320px`, `sm: 640px`, `md: 768px`, `lg: 1024px`, `xl: 1280px`
- **Touch targets** ≥ 44×44px
- **Dark/Light mode** : palettes calibrées, contrastes WCAG AA
---
## 🗂️ Arborescence mise à jour (ajouts clés)
```diff
src/app/features/
├── sidebar/
│ └── app-workspace-selector.component.ts ← [NEW]
├── search-bar/
│ ├── app-filter-chip.component.ts ← [NEW]
│ └── app-picker-overlay.component.ts ← [NEW]
├── note-view/
│ └── app-note-actions-bar.component.ts ← [NEW: Share, Portal, AI]
└── bookmarks/
└── app-bookmark-card.component.ts ← [NEW: rich preview]
```
---
## ✅ Critères dacceptation mis à jour
### Fonctionnels
- [ ] Filtres **persistants** et **éditables** via chips
- [ ] Pickers **avec recherche locale** et **Clear/Done**
- [ ] Boutons **Share** et **Add to portal** toujours visibles dans léditeur
- [ ] **Workspace switcher** dans le rail gauche (desktop) ou menu (mobile)
- [ ] **Bookmark cards** enrichies (titre + description + vignette)
### Techniques
- [ ] Aucune régression sur les features legacy (graph, wikilinks…)
- [ ] État UI (filtres, sélection, workspace) persisté **indépendamment du mode**
- [ ] Virtual scroll fluide (≥60fps) sur 1000+ items
- [ ] Lighthouse Mobile ≥ 85 perf, ≥ 95 a11y
---
## 📖 Documentation à produire
- **README_UI.md** : schémas 3 breakpoints + explication des 8 principes Nimbus
- **MOBILE_GUIDE.md** : flow de navigation tactile, gestures, drawer patterns
- **NIMBUS_SPEC.md** : tokens couleur, tailles de typo, comportements exacts des pickers/chips
---
## 💡 Notes finales
- **Ne pas surcharger lécran** : cacher les actions rares (kebab menu, hover-reveal)
- **Feedback utilisateur** : badges de comptage, messages “Found pages: N”, Clear partout
- **Continuum édition → diffusion** : `Share` et `Add to portal` doivent être **immédiatement accessibles**
---
**Exécute ce plan** : implémente les composants, connecte les états (filtres, workspace, sélection), assure la compatibilité totale Desktop/Mobile, et livre un MR conforme aux 8 principes Nimbus + checklist qualité.