Skip to content

Commit 1826c25

Browse files
authored
Merge pull request #763 from ZenUml/feature/close-tab
feat(PageTabs): add DeletePageModal for confirming page closure and integrate with PageTabs component
2 parents ae232c1 + d74d561 commit 1826c25

File tree

4 files changed

+154
-39
lines changed

4 files changed

+154
-39
lines changed

src/components/ContentWrap.jsx

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1134,6 +1134,7 @@ export default class ContentWrap extends Component {
11341134
currentPageId={this.props.currentItem.currentPageId}
11351135
onTabClick={this.props.onPageSwitch}
11361136
onAddPage={this.props.onAddPage}
1137+
onDeletePage={this.props.onDeletePage}
11371138
/>
11381139
)}
11391140
<div

src/components/DeletePageModal.jsx

Lines changed: 59 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,59 @@
1+
import * as Dialog from '@radix-ui/react-dialog';
2+
3+
export default function DeletePageModal({ open, onClose, onConfirm }) {
4+
return (
5+
<Dialog.Root open={open} onOpenChange={onClose}>
6+
<Dialog.Portal>
7+
<Dialog.Overlay className="bg-black/50 backdrop-blur-sm data-[state=open]:animate-overlayShow fixed inset-0" />
8+
<Dialog.Content className="text-gray-400 data-[state=open]:animate-contentShow fixed top-[50%] left-[50%] max-h-[85vh] w-[90vw] overflow-hidden max-w-[450px] translate-x-[-50%] translate-y-[-50%] rounded-[6px] bg-black-500/90 backdrop-blur p-[25px] shadow-[hsl(206_22%_7%_/_35%)_0px_10px_38px_-10px,_hsl(206_22%_7%_/_20%)_0px_10px_20px_-15px] focus:outline-none">
9+
<Dialog.Title className="text-white m-0 text-[17px] font-medium">
10+
<svg
11+
xmlns="http://www.w3.org/2000/svg"
12+
className="h-6 w-6 text-red-500 inline-block mr-2"
13+
fill="none"
14+
viewBox="0 0 24 24"
15+
stroke="currentColor"
16+
>
17+
<path
18+
strokeLinecap="round"
19+
strokeLinejoin="round"
20+
strokeWidth={2}
21+
d="M12 9v2m0 4h.01m-6.938 4h13.856c1.54 0 2.502-1.667 1.732-3L13.732 4c-.77-1.333-2.694-1.333-3.464 0L3.34 16c-.77 1.333.192 3 1.732 3z"
22+
/>
23+
</svg>
24+
Confirm to Delete
25+
</Dialog.Title>
26+
<Dialog.Description className="text-gray-400 mt-[10px] mb-5 text-[15px] leading-normal">
27+
Are you sure you want to delete this page? The data on this page will be lost forever.
28+
</Dialog.Description>
29+
<div className="flex justify-end gap-[25px]">
30+
<button
31+
className="text-gray-400 bg-transparent border border-gray-400 px-3 py-2 rounded-lg hover:bg-gray-800 hover:text-gray-100 duration-200"
32+
onClick={onClose}
33+
>
34+
Cancel
35+
</button>
36+
<button
37+
className="flex items-center text-white bg-red-600 border border-red-600 px-3 py-2 rounded-lg hover:bg-red-700 duration-200 gap-1"
38+
onClick={onConfirm}
39+
>
40+
<span>Delete</span>
41+
<svg
42+
xmlns="http://www.w3.org/2000/svg"
43+
className="h-4 w-4"
44+
fill="none"
45+
viewBox="0 0 24 24"
46+
stroke="currentColor">
47+
<path
48+
strokeLinecap="round"
49+
strokeLinejoin="round"
50+
strokeWidth="2"
51+
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" />
52+
</svg>
53+
</button>
54+
</div>
55+
</Dialog.Content>
56+
</Dialog.Portal>
57+
</Dialog.Root>
58+
);
59+
}

src/components/PageTabs.jsx

Lines changed: 93 additions & 39 deletions
Original file line numberDiff line numberDiff line change
@@ -1,58 +1,112 @@
1-
import { h } from 'preact';
1+
import { Component } from 'preact';
2+
import DeletePageModal from './DeletePageModal';
23

34
/**
45
* 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
116
*/
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+
};
1612

1713
/**
1814
* Wrapper for the onAddPage callback to properly handle the event object.
1915
* This prevents the synthetic event from being passed to the App's addNewPage method,
2016
* which expects either no parameters or a title string, not an event object.
2117
* Without this wrapper, the event object would cause errors when passed to addNewPage.
2218
*/
23-
const handleAddPage = (e) => {
19+
handleAddPage = (e) => {
2420
e.preventDefault();
2521
e.stopPropagation();
26-
if (typeof onAddPage === 'function') {
27-
onAddPage();
22+
if (typeof this.props.onAddPage === 'function') {
23+
this.props.onAddPage();
2824
}
2925
};
3026

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+
}
56110
}
57111

58112
export default PageTabs;

src/components/app.jsx

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1732,6 +1732,7 @@ BookLibService.Borrow(id) {
17321732
onProFeature={this.proBtnClickHandler.bind(this)}
17331733
onPageSwitch={this.switchToPage.bind(this)}
17341734
onAddPage={this.addNewPage.bind(this)}
1735+
onDeletePage={this.deletePage.bind(this)}
17351736
keyboardShortcutsBtnClickHandler={this.handleShortcutsModalOpen.bind(
17361737
this,
17371738
)}

0 commit comments

Comments
 (0)