|
1 | | -import { h } from 'preact'; |
| 1 | +import { Component } from 'preact'; |
| 2 | +import DeletePageModal from './DeletePageModal'; |
2 | 3 |
|
3 | 4 | /** |
4 | 5 | * PageTabs component displays tabs for each page and handles tab switching |
5 | | - * |
6 | | - * @param {Object} props - Component props |
7 | | - * @param {Array} props.pages - Array of page objects |
8 | | - * @param {String} props.currentPageId - ID of the currently active page |
9 | | - * @param {Function} props.onTabClick - Callback function when a tab is clicked |
10 | | - * @param {Function} props.onAddPage - Callback function when the add page button is clicked |
11 | 6 | */ |
12 | | -export function PageTabs({ pages, currentPageId, onTabClick, onAddPage }) { |
13 | | - if (!pages || pages.length === 0) { |
14 | | - return null; |
15 | | - } |
| 7 | +export class PageTabs extends Component { |
| 8 | + state = { |
| 9 | + isCloseModalOpen: false, |
| 10 | + pageToClose: null, |
| 11 | + }; |
16 | 12 |
|
17 | 13 | /** |
18 | 14 | * Wrapper for the onAddPage callback to properly handle the event object. |
19 | 15 | * This prevents the synthetic event from being passed to the App's addNewPage method, |
20 | 16 | * which expects either no parameters or a title string, not an event object. |
21 | 17 | * Without this wrapper, the event object would cause errors when passed to addNewPage. |
22 | 18 | */ |
23 | | - const handleAddPage = (e) => { |
| 19 | + handleAddPage = (e) => { |
24 | 20 | e.preventDefault(); |
25 | 21 | e.stopPropagation(); |
26 | | - if (typeof onAddPage === 'function') { |
27 | | - onAddPage(); |
| 22 | + if (typeof this.props.onAddPage === 'function') { |
| 23 | + this.props.onAddPage(); |
28 | 24 | } |
29 | 25 | }; |
30 | 26 |
|
31 | | - return ( |
32 | | - <div className="page-tabs bg-black-500 border-b border-black-700 px-2 py-1 flex overflow-x-auto items-center"> |
33 | | - {pages.map(page => ( |
34 | | - <button |
35 | | - key={page.id} |
36 | | - className={`px-4 py-2 mx-1 rounded-t-lg text-sm font-medium transition-colors duration-200 ${ |
37 | | - page.id === currentPageId |
38 | | - ? 'bg-primary text-white' |
39 | | - : 'bg-black-600 text-gray-400 hover:bg-black-700 hover:text-gray-300' |
40 | | - }`} |
41 | | - onClick={() => onTabClick(page.id)} |
42 | | - > |
43 | | - {page.title || 'Untitled'} |
44 | | - </button> |
45 | | - ))} |
46 | | - <button |
47 | | - className="ml-2 px-3 py-2 bg-black-600 text-gray-400 hover:bg-black-700 hover:text-gray-300 rounded-lg text-sm font-medium transition-colors duration-200 flex items-center" |
48 | | - onClick={handleAddPage} |
49 | | - title="Add new page" |
50 | | - > |
51 | | - <span className="mr-1 font-bold text-lg leading-none">+</span> |
52 | | - Add Page |
53 | | - </button> |
54 | | - </div> |
55 | | - ); |
| 27 | + handleDeleteClick = (e, pageId) => { |
| 28 | + e.preventDefault(); |
| 29 | + e.stopPropagation(); |
| 30 | + this.setState({ pageToClose: pageId, isCloseModalOpen: true }); |
| 31 | + }; |
| 32 | + |
| 33 | + handleConfirmDelete = () => { |
| 34 | + if (this.state.pageToClose) { |
| 35 | + this.props.onDeletePage(this.state.pageToClose); |
| 36 | + } |
| 37 | + this.setState({ isCloseModalOpen: false, pageToClose: null }); |
| 38 | + }; |
| 39 | + |
| 40 | + handleCancelDelete = () => { |
| 41 | + this.setState({ isCloseModalOpen: false, pageToClose: null }); |
| 42 | + }; |
| 43 | + |
| 44 | + render() { |
| 45 | + const { pages, currentPageId, onTabClick } = this.props; |
| 46 | + const { isCloseModalOpen } = this.state; |
| 47 | + |
| 48 | + if (!pages || pages.length === 0) { |
| 49 | + return null; |
| 50 | + } |
| 51 | + |
| 52 | + return ( |
| 53 | + <> |
| 54 | + <div className="page-tabs bg-black-500 border-b border-black-700 px-2 py-1 flex overflow-x-auto items-center"> |
| 55 | + {pages.map((page, index) => { |
| 56 | + return ( |
| 57 | + <div |
| 58 | + key={page.id} |
| 59 | + className={`relative flex items-center group rounded-t-lg group mx-1 px-3 py-2 gap-2 ${page.id === currentPageId ? 'bg-primary' : 'bg-black-600'} ${index === 0 ? '' : 'pr-7'}`} |
| 60 | + > |
| 61 | + <button |
| 62 | + className={`text-sm font-medium w-full h-full ${page.id === currentPageId |
| 63 | + ? 'text-white' |
| 64 | + : 'text-gray-400'}`} |
| 65 | + onClick={() => onTabClick(page.id)} |
| 66 | + > |
| 67 | + {page.title || 'Untitled'} |
| 68 | + </button> |
| 69 | + {index !== 0 && <button |
| 70 | + onClick={(e) => this.handleDeleteClick(e, page.id)} |
| 71 | + className={`p-1 rounded-full opacity-0 group-hover:opacity-100 absolute right-1 top-1/2 -translate-y-1/2 ${page.id === currentPageId |
| 72 | + ? 'text-white' |
| 73 | + : 'text-gray-400'}`} |
| 74 | + title="Delete page" |
| 75 | + > |
| 76 | + <svg |
| 77 | + xmlns="http://www.w3.org/2000/svg" |
| 78 | + className="h-4 w-4" |
| 79 | + fill="none" |
| 80 | + viewBox="0 0 24 24" |
| 81 | + stroke="currentColor" |
| 82 | + > |
| 83 | + <path |
| 84 | + strokeLinecap="round" |
| 85 | + strokeLinejoin="round" |
| 86 | + strokeWidth="2" |
| 87 | + d="M19 7l-.867 12.142A2 2 0 0116.138 21H7.862a2 2 0 01-1.995-1.858L5 7m5 4v6m4-6v6m1-10V4a1 1 0 00-1-1h-4a1 1 0 00-1 1v3M4 7h16" /> |
| 88 | + </svg> |
| 89 | + </button>} |
| 90 | + </div> |
| 91 | + ); |
| 92 | + })} |
| 93 | + <button |
| 94 | + className="ml-1 px-3 py-2 bg-black-600 text-gray-400 hover:bg-black-700 hover:text-gray-300 rounded-lg text-sm font-medium transition-colors duration-200 flex items-center" |
| 95 | + onClick={this.handleAddPage} |
| 96 | + title="Add new page" |
| 97 | + > |
| 98 | + <span className="mr-1 font-bold text-lg leading-none">+</span> |
| 99 | + Add Page |
| 100 | + </button> |
| 101 | + </div> |
| 102 | + <DeletePageModal |
| 103 | + open={isCloseModalOpen} |
| 104 | + onClose={this.handleCancelDelete} |
| 105 | + onConfirm={this.handleConfirmDelete} |
| 106 | + /> |
| 107 | + </> |
| 108 | + ); |
| 109 | + } |
56 | 110 | } |
57 | 111 |
|
58 | 112 | export default PageTabs; |
0 commit comments