remove dnd-kit; add draggable tabs
This commit is contained in:
@ -1,11 +1,13 @@
|
||||
import { Tab, TabList } from "@fluentui/react-tabs";
|
||||
import MapComponent from "../components/map/MapComponent";
|
||||
import { DragDropContext, Droppable, Draggable } from "@hello-pangea/dnd";
|
||||
|
||||
import {
|
||||
useAppStore,
|
||||
setCurrentTab,
|
||||
deleteMapTab,
|
||||
addMapTab,
|
||||
reorderTabs,
|
||||
} from "../store/app";
|
||||
import { initializeMapState, useMapStore } from "../store/map";
|
||||
import { initializeObjectsState } from "../store/objects";
|
||||
@ -13,9 +15,86 @@ import { Button } from "@fluentui/react-components";
|
||||
import { Add12Filled, Dismiss12Filled, Map16Regular } from "@fluentui/react-icons";
|
||||
|
||||
function MapTest() {
|
||||
const { mapTab, currentTab } = useAppStore()
|
||||
const { mapTab, currentTab, tabOrder } = useAppStore()
|
||||
const { id } = useMapStore()
|
||||
|
||||
const handleDragEnd = (result: any) => {
|
||||
if (!result.destination) return
|
||||
reorderTabs(result.source.index, result.destination.index)
|
||||
}
|
||||
|
||||
return (
|
||||
<div style={{ height: "100%", width: "100%", position: "relative" }}>
|
||||
<div style={{ display: "flex", flexDirection: "column", height: "100%" }}>
|
||||
<DragDropContext onDragEnd={handleDragEnd}>
|
||||
<Droppable droppableId="tabs" direction="horizontal">
|
||||
{(provided) => (
|
||||
<TabList
|
||||
ref={provided.innerRef}
|
||||
{...provided.droppableProps}
|
||||
size="small"
|
||||
selectedValue={currentTab}
|
||||
onTabSelect={(_, data) => setCurrentTab(data.value as string)}
|
||||
style={{ borderBottom: '1px solid var(--colorNeutralShadowKey)' }}
|
||||
onDragStart={(e) => {
|
||||
e.stopPropagation(); // stop TabList from also handling it
|
||||
}}
|
||||
onDrag={(e) => e.stopPropagation()}
|
||||
>
|
||||
{tabOrder.map((key, index) => (
|
||||
<Draggable disableInteractiveElementBlocking draggableId={key} index={index} key={key}>
|
||||
{(dragProvided) => (
|
||||
<div
|
||||
ref={dragProvided.innerRef}
|
||||
{...dragProvided.draggableProps}
|
||||
{...dragProvided.dragHandleProps}
|
||||
>
|
||||
<Tab value={key} icon={<Map16Regular />}>
|
||||
{id[key]?.mapLabel ?? `Tab ${key}`}
|
||||
<Button
|
||||
style={{ marginLeft: '0.5rem' }}
|
||||
size="small"
|
||||
icon={<Dismiss12Filled />}
|
||||
appearance="subtle"
|
||||
onClick={(e) => {
|
||||
e.stopPropagation()
|
||||
deleteMapTab(key)
|
||||
}}
|
||||
/>
|
||||
</Tab>
|
||||
</div>
|
||||
)}
|
||||
</Draggable>
|
||||
))}
|
||||
|
||||
{provided.placeholder}
|
||||
|
||||
<Button
|
||||
icon={<Add12Filled />}
|
||||
title="Открыть новую вкладку"
|
||||
appearance="subtle"
|
||||
onClick={() => {
|
||||
const newId = addMapTab();
|
||||
initializeObjectsState(newId, null, null, null, null);
|
||||
initializeMapState(newId);
|
||||
}}
|
||||
/>
|
||||
</TabList>
|
||||
)}
|
||||
</Droppable>
|
||||
</DragDropContext>
|
||||
|
||||
<div style={{ flexGrow: 1, position: "relative" }}>
|
||||
{tabOrder.map((key) => (
|
||||
<div key={key} style={{ height: "100%", position: "relative", display: currentTab === key ? 'unset' : 'none' }}>
|
||||
<MapComponent id={key} active={currentTab === key} />
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
)
|
||||
|
||||
return (
|
||||
<div style={{ height: "100%", width: "100%", position: "relative" }}>
|
||||
<div style={{ display: "flex", flexDirection: "column", height: "100%" }}>
|
||||
|
@ -4,7 +4,6 @@ import { initializeObjectsState } from './objects'
|
||||
import { initializeMapState } from './map'
|
||||
|
||||
export type Mode = 'edit' | 'view'
|
||||
|
||||
export type ColorScheme = 'light' | 'dark' | 'auto'
|
||||
|
||||
export interface MapTabState {
|
||||
@ -14,15 +13,16 @@ export interface MapTabState {
|
||||
}
|
||||
|
||||
export interface AppState {
|
||||
colorScheme: ColorScheme,
|
||||
mapTab: Record<string, MapTabState>,
|
||||
currentTab: string | null;
|
||||
colorScheme: ColorScheme
|
||||
mapTab: Record<string, MapTabState>
|
||||
tabOrder: string[] // 👈 defines tab order
|
||||
currentTab: string | null
|
||||
}
|
||||
|
||||
export const useAppStore = create<AppState>(() => {
|
||||
const firstId = uuidv4()
|
||||
|
||||
initializeObjectsState(firstId, null, null, null, null);
|
||||
initializeObjectsState(firstId, null, null, null, null)
|
||||
initializeMapState(firstId)
|
||||
|
||||
return {
|
||||
@ -31,15 +31,15 @@ export const useAppStore = create<AppState>(() => {
|
||||
mapTab: {
|
||||
[firstId]: { year: null, region: null, district: null },
|
||||
},
|
||||
tabOrder: [firstId],
|
||||
}
|
||||
})
|
||||
|
||||
export const getColorScheme = () => {
|
||||
useAppStore.getState().colorScheme
|
||||
}
|
||||
// getters/setters
|
||||
export const getColorScheme = () => useAppStore.getState().colorScheme
|
||||
|
||||
export const setColorScheme = (colorScheme: ColorScheme) => {
|
||||
useAppStore.setState(() => ({ colorScheme: colorScheme }))
|
||||
useAppStore.setState(() => ({ colorScheme }))
|
||||
localStorage.setItem('colorScheme', colorScheme.toString())
|
||||
}
|
||||
|
||||
@ -47,40 +47,46 @@ export const getCurrentTab = () => useAppStore.getState().currentTab
|
||||
export const setCurrentTab = (id: string | null) => useAppStore.setState(() => ({ currentTab: id }))
|
||||
|
||||
export const setMapTabYear = (id: string, year: number | null) =>
|
||||
useAppStore.setState((state) => {
|
||||
return {
|
||||
mapTab: {
|
||||
...state.mapTab,
|
||||
[id]: { ...state.mapTab[id], year: year }
|
||||
}
|
||||
}
|
||||
})
|
||||
useAppStore.setState((state) => ({
|
||||
mapTab: {
|
||||
...state.mapTab,
|
||||
[id]: { ...state.mapTab[id], year },
|
||||
},
|
||||
}))
|
||||
|
||||
export const deleteMapTab = (id: string) =>
|
||||
useAppStore.setState((state) => {
|
||||
const { [id]: _, ...remainingTabs } = state.mapTab;
|
||||
const keys = Object.keys(remainingTabs);
|
||||
const { [id]: _, ...remainingTabs } = state.mapTab
|
||||
const newOrder = state.tabOrder.filter((tid) => tid !== id)
|
||||
|
||||
return {
|
||||
mapTab: remainingTabs,
|
||||
currentTab: keys.length > 0 ? keys[keys.length - 1] : null,
|
||||
};
|
||||
tabOrder: newOrder,
|
||||
currentTab: newOrder.length > 0 ? newOrder[newOrder.length - 1] : null,
|
||||
}
|
||||
})
|
||||
|
||||
export const addMapTab = () => {
|
||||
const id = uuidv4();
|
||||
const id = uuidv4()
|
||||
initializeObjectsState(id, null, null, null, null)
|
||||
initializeMapState(id)
|
||||
|
||||
useAppStore.setState((state) => ({
|
||||
mapTab: {
|
||||
...state.mapTab,
|
||||
[id]: {
|
||||
year: null,
|
||||
region: null,
|
||||
district: null,
|
||||
},
|
||||
[id]: { year: null, region: null, district: null },
|
||||
},
|
||||
currentTab: id, // optionally switch to this new tab
|
||||
}));
|
||||
tabOrder: [...state.tabOrder, id],
|
||||
currentTab: id,
|
||||
}))
|
||||
|
||||
return id; // so you can use the new id in your components
|
||||
}
|
||||
return id
|
||||
}
|
||||
|
||||
export const reorderTabs = (from: number, to: number) =>
|
||||
useAppStore.setState((state) => {
|
||||
const newOrder = Array.from(state.tabOrder)
|
||||
const [moved] = newOrder.splice(from, 1)
|
||||
newOrder.splice(to, 0, moved)
|
||||
return { tabOrder: newOrder }
|
||||
})
|
||||
|
Reference in New Issue
Block a user