@@ -8,7 +8,8 @@ Tabs for the open files in a project.
88*/
99
1010import type { MenuProps , TabsProps } from "antd" ;
11- import { Dropdown , Tabs } from "antd" ;
11+ import { Button , Dropdown , Tabs } from "antd" ;
12+ import { useState } from "react" ;
1213import { useIntl } from "react-intl" ;
1314
1415import {
@@ -30,8 +31,9 @@ import {
3031 type OpenedFile ,
3132} from "@cocalc/frontend/projects/util" ;
3233import { EDITOR_PREFIX , path_to_tab } from "@cocalc/util/misc" ;
34+ import { COLORS } from "@cocalc/util/theme" ;
3335import { file_tab_labels } from "../file-tab-labels" ;
34- import { FileTab } from "./file-tab" ;
36+ import { FileTab , FIXED_PROJECT_TABS } from "./file-tab" ;
3537
3638const MIN_WIDTH = 48 ;
3739
@@ -76,6 +78,7 @@ function keyToPath(s: string): string {
7678export default function FileTabs ( { openFiles, project_id, activeTab } ) {
7779 const intl = useIntl ( ) ;
7880 const actions = useActions ( { project_id } ) ;
81+ const [ recentFilesMenuOpen , setRecentFilesMenuOpen ] = useState ( false ) ;
7982 const project_log = useTypedRedux ( { project_id } , "project_log" ) ;
8083 const directory_listings = useTypedRedux (
8184 { project_id } ,
@@ -105,6 +108,7 @@ export default function FileTabs({ openFiles, project_id, activeTab }) {
105108 paths . push ( path ) ;
106109 keys . push ( pathToKey ( path ) ) ;
107110 } ) ;
111+ const openPathSet = new Set ( paths ) ;
108112
109113 const labels = file_tab_labels ( paths ) ;
110114 const items : TabsProps [ "items" ] = [ ] ;
@@ -170,7 +174,31 @@ export default function FileTabs({ openFiles, project_id, activeTab }) {
170174 }
171175
172176 function getRecentFilesMenu ( ) : MenuProps {
173- const menuItems : MenuProps [ "items" ] = recentFiles . map (
177+ const closedRecentFiles = recentFiles . filter (
178+ ( entry : OpenedFile ) => ! openPathSet . has ( entry . filename ) ,
179+ ) ;
180+ const actionItems : MenuProps [ "items" ] = [
181+ {
182+ key : "browse-existing-files" ,
183+ icon : < Icon name = { FIXED_PROJECT_TABS . files . icon } /> ,
184+ label : intl . formatMessage ( i18nLabels . file_explorer ) ,
185+ onClick : ( ) => actions ?. set_active_tab ( "files" ) ,
186+ } ,
187+ {
188+ key : "create-new-file" ,
189+ icon : < Icon name = { FIXED_PROJECT_TABS . new . icon } /> ,
190+ label : intl . formatMessage ( i18nLabels . new_tooltip ) ,
191+ onClick : ( ) => actions ?. set_active_tab ( "new" ) ,
192+ } ,
193+ ] ;
194+
195+ if ( closedRecentFiles . length === 0 ) {
196+ return {
197+ items : actionItems ,
198+ } ;
199+ }
200+
201+ const menuItems : MenuProps [ "items" ] = closedRecentFiles . map (
174202 ( entry : OpenedFile ) => {
175203 const icon = file_options ( entry . filename ) ?. icon ?? "file" ;
176204 return {
@@ -196,13 +224,53 @@ export default function FileTabs({ openFiles, project_id, activeTab }) {
196224 label : intl . formatMessage ( i18nLabels . recent_files ) ,
197225 children : menuItems ,
198226 } ,
227+ {
228+ key : "recent-files-divider" ,
229+ type : "divider" ,
230+ } ,
231+ ...actionItems ,
199232 ] ,
200233 style : { maxHeight : "min(500px, 50vh)" , overflowY : "auto" } ,
201234 } ;
202235 }
203236
237+ const recentFilesMenu = getRecentFilesMenu ( ) ;
238+
239+ function renderExtra ( ) {
240+ return {
241+ right : (
242+ < div
243+ style = { {
244+ display : "flex" ,
245+ alignItems : "center" ,
246+ marginRight : "10px" ,
247+ marginLeft : "10px" ,
248+ } }
249+ >
250+ < Dropdown
251+ trigger = { [ "click" ] }
252+ menu = { recentFilesMenu }
253+ onOpenChange = { setRecentFilesMenuOpen }
254+ >
255+ < Button
256+ type = "text"
257+ size = "small"
258+ icon = { < Icon name = "down-circle-o" /> }
259+ style = { {
260+ paddingInline : "10px" ,
261+ ...( recentFilesMenuOpen
262+ ? { backgroundColor : COLORS . GRAY_LL }
263+ : { } ) ,
264+ } }
265+ />
266+ </ Dropdown >
267+ </ div >
268+ ) ,
269+ } ;
270+ }
271+
204272 return (
205- < Dropdown trigger = { [ "contextMenu" ] } menu = { getRecentFilesMenu ( ) } >
273+ < Dropdown trigger = { [ "contextMenu" ] } menu = { recentFilesMenu } >
206274 < div style = { { width : "100%" } } >
207275 < SortableTabs
208276 items = { keys }
@@ -223,6 +291,7 @@ export default function FileTabs({ openFiles, project_id, activeTab }) {
223291 items = { items }
224292 activeKey = { activeKey }
225293 type = { "editable-card" }
294+ tabBarExtraContent = { renderExtra ( ) }
226295 onChange = { ( key ) => {
227296 if ( actions == null ) return ;
228297 actions . set_active_tab ( path_to_tab ( keyToPath ( key ) ) ) ;
0 commit comments