fix: lỗi hiển thị trong itineraryTimeline
This commit is contained in:
@@ -0,0 +1,142 @@
|
||||
# To AI Agent: Refactor Itinerary Timeline into an Exclusive File Tree Directory System (Single Expansion Mode)
|
||||
|
||||
## 1. Context & Architectural Analogy
|
||||
We are refactoring the `ItineraryTimeline` component on the mobile view (`yotrip.labz.io.vn`) using a **File Tree Directory System** analogy:
|
||||
- **Parent Folders ("Thư mục mẹ"):** Represented by the Stages ("Chặng 1", "Chặng 2"...).
|
||||
- **Child Nodes ("Thư mục con"):** Represented by the Locations/Destinations inside that stage (`Trần Cao Vân`, `Đồng Khởi`...).
|
||||
|
||||
### CRITICAL LOGIC CONSTRAINT (Exclusive Accordion):
|
||||
- When a Parent Folder (Stage) is **collapsed**, all of its Child Nodes (Locations) must immediately hide cleanly inside it.
|
||||
- **Single Expansion Rule:** The system must enforce an **exclusive single-expansion mode**. On the entire timeline screen, **MAXIMUM ONE** Parent Folder can be expanded at any given time.
|
||||
- Opening/Expanding a new Stage folder must **automatically collapse** whichever Stage folder was previously open.
|
||||
|
||||
---
|
||||
|
||||
## 2. State Management Specification (For Script/Logic Implementation)
|
||||
|
||||
To enforce the "Maximum 1 Expanded Folder" rule, do NOT use isolated individual boolean flags for each stage. Instead, implement a centralized single-active-state variable:
|
||||
|
||||
```javascript
|
||||
// Example React State Hook Blueprint:
|
||||
// Track the ID or index of the single active expanded stage folder.
|
||||
// If null, all stages are collapsed.
|
||||
const [expandedStageId, setExpandedStageId] = useState(initialStageId);
|
||||
|
||||
const handleStageToggle = (stageId) => {
|
||||
// If clicking the already open folder, close it. Otherwise, open the new one and shut the rest.
|
||||
setExpandedStageId(prevId => prevId === stageId ? null : stageId);
|
||||
};
|
||||
|
||||
## 3. Component DOM Tree & CSS Blueprint
|
||||
### A. Component Layout Structure
|
||||
|
||||
<div class="file-tree-itinerary-container">
|
||||
|
||||
<div class="fixed-top-header-block">
|
||||
<header class="main-tour-header">...</header>
|
||||
<nav class="sub-navigation-tabs">...</nav>
|
||||
</div>
|
||||
|
||||
<main class="directory-scroll-viewport">
|
||||
|
||||
<section class="folder-node-wrapper collapsed">
|
||||
<div class="folder-header-row" onclick="handleStageToggle('stage_1')">
|
||||
<span class="folder-badge-index">1</span>
|
||||
<h3 class="folder-title">Chặng khởi đầu</h3>
|
||||
</div>
|
||||
<div class="folder-child-content-box">
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<section class="folder-node-wrapper expanded">
|
||||
<div class="folder-header-row" onclick="handleStageToggle('stage_2')">
|
||||
<span class="folder-badge-index">2</span>
|
||||
<h3 class="folder-title">Chặng 2</h3>
|
||||
</div>
|
||||
|
||||
<div class="folder-child-content-box">
|
||||
<div class="child-nodes-list">
|
||||
<div class="location-child-card">Trần Cao Vân</div>
|
||||
<div class="location-child-card">Đồng Khởi</div>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
</main>
|
||||
</div>
|
||||
|
||||
### B. Core CSS Layout Styles
|
||||
|
||||
.file-tree-itinerary-container {
|
||||
display: flex !important;
|
||||
flex-direction: column !important;
|
||||
height: 100dvh !important;
|
||||
width: 100vw !important;
|
||||
overflow: hidden !important;
|
||||
}
|
||||
|
||||
.directory-scroll-viewport {
|
||||
flex: 1 1 0% !important;
|
||||
overflow-y: auto !important;
|
||||
padding: 0 !important;
|
||||
margin: 0 !important;
|
||||
background-color: #f8fafc;
|
||||
}
|
||||
|
||||
/* Base style for folder blocks stacked flush against each other */
|
||||
.folder-node-wrapper {
|
||||
width: 100% !important;
|
||||
background-color: #ffffff;
|
||||
margin-bottom: 1px !important; /* Micro hair-line divider between folders */
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
}
|
||||
|
||||
.folder-header-row {
|
||||
width: 100%;
|
||||
padding: 12px 16px !important;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
background-color: #ffffff;
|
||||
cursor: pointer;
|
||||
/* Sticky behavior remains active when scrolling within an open directory */
|
||||
position: sticky !important;
|
||||
top: 0px;
|
||||
z-index: 30;
|
||||
}
|
||||
|
||||
/* CSS Grid Transition Engine for smooth directory expansions */
|
||||
.folder-child-content-box {
|
||||
display: grid !important;
|
||||
grid-template-rows: 0fr;
|
||||
transition: grid-template-rows 0.25s cubic-bezier(0.4, 0, 0.2, 1) !important;
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.child-nodes-list {
|
||||
overflow: hidden;
|
||||
min-height: 0px;
|
||||
padding: 16px;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 12px;
|
||||
}
|
||||
|
||||
/* --- MUTUALLY EXCLUSIVE STATE STYLES --- */
|
||||
|
||||
/* Collapsed Folder: Sub-files shrink immediately to 0 height */
|
||||
.folder-node-wrapper.collapsed .folder-child-content-box {
|
||||
grid-template-rows: 0fr !important;
|
||||
}
|
||||
|
||||
/* Expanded Folder: Opens dynamically to accommodate dynamic content height */
|
||||
.folder-node-wrapper.expanded .folder-child-content-box {
|
||||
grid-template-rows: 1fr !important;
|
||||
}
|
||||
|
||||
## 4. Acceptance Criteria for AI Agent Verification
|
||||
[ ] Mutually Exclusive Test: Clicking an inactive Stage header while another stage is open must trigger a simultaneous transition: the old stage collapses back into a tight header row, and the clicked stage expands its location cards.
|
||||
|
||||
[ ] Zero-Gap Validation: All collapsed folder components must sit completely flush against the top tab block and one another, eliminating all gray margin bleeding.
|
||||
|
||||
[ ] Under-Clip Containment: When scrolling a long open folder, the list items must slide behind their sticky active parent folder row and disappear without visual overlapping artifacts.
|
||||
Reference in New Issue
Block a user