feat: add tab
This commit is contained in:
parent
3c5c93e422
commit
c0ab592944
|
@ -15,6 +15,7 @@
|
||||||
"@radix-ui/react-menubar": "^1.1.1",
|
"@radix-ui/react-menubar": "^1.1.1",
|
||||||
"@radix-ui/react-slot": "^1.1.0",
|
"@radix-ui/react-slot": "^1.1.0",
|
||||||
"@radix-ui/react-toast": "^1.2.1",
|
"@radix-ui/react-toast": "^1.2.1",
|
||||||
|
"@radix-ui/react-tooltip": "^1.1.2",
|
||||||
"class-variance-authority": "^0.7.0",
|
"class-variance-authority": "^0.7.0",
|
||||||
"clsx": "^2.1.1",
|
"clsx": "^2.1.1",
|
||||||
"cmdk": "^1.0.0",
|
"cmdk": "^1.0.0",
|
||||||
|
|
|
@ -20,6 +20,9 @@ importers:
|
||||||
'@radix-ui/react-toast':
|
'@radix-ui/react-toast':
|
||||||
specifier: ^1.2.1
|
specifier: ^1.2.1
|
||||||
version: 1.2.1(@types/react-dom@18.3.0)(@types/react@18.3.3)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)
|
version: 1.2.1(@types/react-dom@18.3.0)(@types/react@18.3.3)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)
|
||||||
|
'@radix-ui/react-tooltip':
|
||||||
|
specifier: ^1.1.2
|
||||||
|
version: 1.1.2(@types/react-dom@18.3.0)(@types/react@18.3.3)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)
|
||||||
class-variance-authority:
|
class-variance-authority:
|
||||||
specifier: ^0.7.0
|
specifier: ^0.7.0
|
||||||
version: 0.7.0
|
version: 0.7.0
|
||||||
|
@ -851,6 +854,19 @@ packages:
|
||||||
'@types/react-dom':
|
'@types/react-dom':
|
||||||
optional: true
|
optional: true
|
||||||
|
|
||||||
|
'@radix-ui/react-tooltip@1.1.2':
|
||||||
|
resolution: {integrity: sha512-9XRsLwe6Yb9B/tlnYCPVUd/TFS4J7HuOZW345DCeC6vKIxQGMZdx21RK4VoZauPD5frgkXTYVS5y90L+3YBn4w==}
|
||||||
|
peerDependencies:
|
||||||
|
'@types/react': '*'
|
||||||
|
'@types/react-dom': '*'
|
||||||
|
react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc
|
||||||
|
react-dom: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc
|
||||||
|
peerDependenciesMeta:
|
||||||
|
'@types/react':
|
||||||
|
optional: true
|
||||||
|
'@types/react-dom':
|
||||||
|
optional: true
|
||||||
|
|
||||||
'@radix-ui/react-use-callback-ref@1.0.1':
|
'@radix-ui/react-use-callback-ref@1.0.1':
|
||||||
resolution: {integrity: sha512-D94LjX4Sp0xJFVaoQOd3OO9k7tpBYNOXdVhkltUbGv2Qb9OXdrg/CpsjlZv7ia14Sylv398LswWBVVu5nqKzAQ==}
|
resolution: {integrity: sha512-D94LjX4Sp0xJFVaoQOd3OO9k7tpBYNOXdVhkltUbGv2Qb9OXdrg/CpsjlZv7ia14Sylv398LswWBVVu5nqKzAQ==}
|
||||||
peerDependencies:
|
peerDependencies:
|
||||||
|
@ -3617,6 +3633,26 @@ snapshots:
|
||||||
'@types/react': 18.3.3
|
'@types/react': 18.3.3
|
||||||
'@types/react-dom': 18.3.0
|
'@types/react-dom': 18.3.0
|
||||||
|
|
||||||
|
'@radix-ui/react-tooltip@1.1.2(@types/react-dom@18.3.0)(@types/react@18.3.3)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)':
|
||||||
|
dependencies:
|
||||||
|
'@radix-ui/primitive': 1.1.0
|
||||||
|
'@radix-ui/react-compose-refs': 1.1.0(@types/react@18.3.3)(react@18.3.1)
|
||||||
|
'@radix-ui/react-context': 1.1.0(@types/react@18.3.3)(react@18.3.1)
|
||||||
|
'@radix-ui/react-dismissable-layer': 1.1.0(@types/react-dom@18.3.0)(@types/react@18.3.3)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)
|
||||||
|
'@radix-ui/react-id': 1.1.0(@types/react@18.3.3)(react@18.3.1)
|
||||||
|
'@radix-ui/react-popper': 1.2.0(@types/react-dom@18.3.0)(@types/react@18.3.3)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)
|
||||||
|
'@radix-ui/react-portal': 1.1.1(@types/react-dom@18.3.0)(@types/react@18.3.3)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)
|
||||||
|
'@radix-ui/react-presence': 1.1.0(@types/react-dom@18.3.0)(@types/react@18.3.3)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)
|
||||||
|
'@radix-ui/react-primitive': 2.0.0(@types/react-dom@18.3.0)(@types/react@18.3.3)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)
|
||||||
|
'@radix-ui/react-slot': 1.1.0(@types/react@18.3.3)(react@18.3.1)
|
||||||
|
'@radix-ui/react-use-controllable-state': 1.1.0(@types/react@18.3.3)(react@18.3.1)
|
||||||
|
'@radix-ui/react-visually-hidden': 1.1.0(@types/react-dom@18.3.0)(@types/react@18.3.3)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)
|
||||||
|
react: 18.3.1
|
||||||
|
react-dom: 18.3.1(react@18.3.1)
|
||||||
|
optionalDependencies:
|
||||||
|
'@types/react': 18.3.3
|
||||||
|
'@types/react-dom': 18.3.0
|
||||||
|
|
||||||
'@radix-ui/react-use-callback-ref@1.0.1(@types/react@18.3.3)(react@18.3.1)':
|
'@radix-ui/react-use-callback-ref@1.0.1(@types/react@18.3.3)(react@18.3.1)':
|
||||||
dependencies:
|
dependencies:
|
||||||
'@babel/runtime': 7.24.8
|
'@babel/runtime': 7.24.8
|
||||||
|
@ -3975,7 +4011,7 @@ snapshots:
|
||||||
|
|
||||||
app-builder-bin@4.0.0: {}
|
app-builder-bin@4.0.0: {}
|
||||||
|
|
||||||
app-builder-lib@24.13.3(dmg-builder@24.13.3(electron-builder-squirrel-windows@24.13.3(dmg-builder@24.13.3)))(electron-builder-squirrel-windows@24.13.3(dmg-builder@24.13.3)):
|
app-builder-lib@24.13.3(dmg-builder@24.13.3(electron-builder-squirrel-windows@24.13.3))(electron-builder-squirrel-windows@24.13.3(dmg-builder@24.13.3)):
|
||||||
dependencies:
|
dependencies:
|
||||||
'@develar/schema-utils': 2.6.5
|
'@develar/schema-utils': 2.6.5
|
||||||
'@electron/notarize': 2.2.1
|
'@electron/notarize': 2.2.1
|
||||||
|
@ -3989,7 +4025,7 @@ snapshots:
|
||||||
builder-util-runtime: 9.2.4
|
builder-util-runtime: 9.2.4
|
||||||
chromium-pickle-js: 0.2.0
|
chromium-pickle-js: 0.2.0
|
||||||
debug: 4.3.5
|
debug: 4.3.5
|
||||||
dmg-builder: 24.13.3(electron-builder-squirrel-windows@24.13.3(dmg-builder@24.13.3))
|
dmg-builder: 24.13.3(electron-builder-squirrel-windows@24.13.3)
|
||||||
ejs: 3.1.10
|
ejs: 3.1.10
|
||||||
electron-builder-squirrel-windows: 24.13.3(dmg-builder@24.13.3)
|
electron-builder-squirrel-windows: 24.13.3(dmg-builder@24.13.3)
|
||||||
electron-publish: 24.13.1
|
electron-publish: 24.13.1
|
||||||
|
@ -4361,9 +4397,9 @@ snapshots:
|
||||||
|
|
||||||
dlv@1.1.3: {}
|
dlv@1.1.3: {}
|
||||||
|
|
||||||
dmg-builder@24.13.3(electron-builder-squirrel-windows@24.13.3(dmg-builder@24.13.3)):
|
dmg-builder@24.13.3(electron-builder-squirrel-windows@24.13.3):
|
||||||
dependencies:
|
dependencies:
|
||||||
app-builder-lib: 24.13.3(dmg-builder@24.13.3(electron-builder-squirrel-windows@24.13.3(dmg-builder@24.13.3)))(electron-builder-squirrel-windows@24.13.3(dmg-builder@24.13.3))
|
app-builder-lib: 24.13.3(dmg-builder@24.13.3(electron-builder-squirrel-windows@24.13.3))(electron-builder-squirrel-windows@24.13.3(dmg-builder@24.13.3))
|
||||||
builder-util: 24.13.1
|
builder-util: 24.13.1
|
||||||
builder-util-runtime: 9.2.4
|
builder-util-runtime: 9.2.4
|
||||||
fs-extra: 10.1.0
|
fs-extra: 10.1.0
|
||||||
|
@ -4403,7 +4439,7 @@ snapshots:
|
||||||
|
|
||||||
electron-builder-squirrel-windows@24.13.3(dmg-builder@24.13.3):
|
electron-builder-squirrel-windows@24.13.3(dmg-builder@24.13.3):
|
||||||
dependencies:
|
dependencies:
|
||||||
app-builder-lib: 24.13.3(dmg-builder@24.13.3(electron-builder-squirrel-windows@24.13.3(dmg-builder@24.13.3)))(electron-builder-squirrel-windows@24.13.3(dmg-builder@24.13.3))
|
app-builder-lib: 24.13.3(dmg-builder@24.13.3(electron-builder-squirrel-windows@24.13.3))(electron-builder-squirrel-windows@24.13.3(dmg-builder@24.13.3))
|
||||||
archiver: 5.3.2
|
archiver: 5.3.2
|
||||||
builder-util: 24.13.1
|
builder-util: 24.13.1
|
||||||
fs-extra: 10.1.0
|
fs-extra: 10.1.0
|
||||||
|
@ -4413,11 +4449,11 @@ snapshots:
|
||||||
|
|
||||||
electron-builder@24.13.3(electron-builder-squirrel-windows@24.13.3(dmg-builder@24.13.3)):
|
electron-builder@24.13.3(electron-builder-squirrel-windows@24.13.3(dmg-builder@24.13.3)):
|
||||||
dependencies:
|
dependencies:
|
||||||
app-builder-lib: 24.13.3(dmg-builder@24.13.3(electron-builder-squirrel-windows@24.13.3(dmg-builder@24.13.3)))(electron-builder-squirrel-windows@24.13.3(dmg-builder@24.13.3))
|
app-builder-lib: 24.13.3(dmg-builder@24.13.3(electron-builder-squirrel-windows@24.13.3))(electron-builder-squirrel-windows@24.13.3(dmg-builder@24.13.3))
|
||||||
builder-util: 24.13.1
|
builder-util: 24.13.1
|
||||||
builder-util-runtime: 9.2.4
|
builder-util-runtime: 9.2.4
|
||||||
chalk: 4.1.2
|
chalk: 4.1.2
|
||||||
dmg-builder: 24.13.3(electron-builder-squirrel-windows@24.13.3(dmg-builder@24.13.3))
|
dmg-builder: 24.13.3(electron-builder-squirrel-windows@24.13.3)
|
||||||
fs-extra: 10.1.0
|
fs-extra: 10.1.0
|
||||||
is-ci: 3.0.1
|
is-ci: 3.0.1
|
||||||
lazy-val: 1.0.5
|
lazy-val: 1.0.5
|
||||||
|
|
30
src/components/ui/tooltip.tsx
Normal file
30
src/components/ui/tooltip.tsx
Normal file
|
@ -0,0 +1,30 @@
|
||||||
|
"use client"
|
||||||
|
|
||||||
|
import * as React from "react"
|
||||||
|
import * as TooltipPrimitive from "@radix-ui/react-tooltip"
|
||||||
|
|
||||||
|
import { cn } from "@/lib/utils"
|
||||||
|
|
||||||
|
const TooltipProvider = TooltipPrimitive.Provider
|
||||||
|
|
||||||
|
const Tooltip = TooltipPrimitive.Root
|
||||||
|
|
||||||
|
const TooltipTrigger = TooltipPrimitive.Trigger
|
||||||
|
|
||||||
|
const TooltipContent = React.forwardRef<
|
||||||
|
React.ElementRef<typeof TooltipPrimitive.Content>,
|
||||||
|
React.ComponentPropsWithoutRef<typeof TooltipPrimitive.Content>
|
||||||
|
>(({ className, sideOffset = 4, ...props }, ref) => (
|
||||||
|
<TooltipPrimitive.Content
|
||||||
|
ref={ref}
|
||||||
|
sideOffset={sideOffset}
|
||||||
|
className={cn(
|
||||||
|
"z-50 overflow-hidden rounded-md bg-primary px-3 py-1.5 text-xs text-primary-foreground animate-in fade-in-0 zoom-in-95 data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=closed]:zoom-out-95 data-[side=bottom]:slide-in-from-top-2 data-[side=left]:slide-in-from-right-2 data-[side=right]:slide-in-from-left-2 data-[side=top]:slide-in-from-bottom-2",
|
||||||
|
className
|
||||||
|
)}
|
||||||
|
{...props}
|
||||||
|
/>
|
||||||
|
))
|
||||||
|
TooltipContent.displayName = TooltipPrimitive.Content.displayName
|
||||||
|
|
||||||
|
export { Tooltip, TooltipTrigger, TooltipContent, TooltipProvider }
|
|
@ -1,14 +1,23 @@
|
||||||
import React from "react";
|
import React from "react";
|
||||||
import { IJsonModel, Layout, Model, TabNode } from "flexlayout-react";
|
import { Actions, BorderNode, DockLocation, IJsonModel, ITabRenderValues, ITabSetRenderValues, Layout, Model, TabNode, TabSetNode } from "flexlayout-react";
|
||||||
import "flexlayout-react/style/light.css";
|
import "flexlayout-react/style/light.css";
|
||||||
import "./Layout.css";
|
import "./Layout.css";
|
||||||
|
import { Button } from "@/components/ui/button"
|
||||||
|
import {
|
||||||
|
Tooltip,
|
||||||
|
TooltipContent,
|
||||||
|
TooltipProvider,
|
||||||
|
TooltipTrigger,
|
||||||
|
} from "@/components/ui/tooltip"
|
||||||
|
|
||||||
const json: IJsonModel = {
|
const json: IJsonModel = {
|
||||||
global: {
|
global: {
|
||||||
tabEnableFloat: false,
|
tabEnableFloat: false,
|
||||||
tabSetMinWidth: 100,
|
tabSetMinWidth: 100,
|
||||||
tabSetMinHeight: 100,
|
tabSetMinHeight: 200,
|
||||||
|
tabSetTabStripHeight: 48,//tab栏高度
|
||||||
borderMinSize: 100,
|
borderMinSize: 100,
|
||||||
|
splitterSize: 2,
|
||||||
},
|
},
|
||||||
borders: [],
|
borders: [],
|
||||||
layout: {
|
layout: {
|
||||||
|
@ -21,8 +30,10 @@ const json: IJsonModel = {
|
||||||
children: [
|
children: [
|
||||||
{
|
{
|
||||||
type: "tab",
|
type: "tab",
|
||||||
|
id: 'tab1',
|
||||||
name: "One",
|
name: "One",
|
||||||
component: "button",
|
component: "tabComponent",
|
||||||
|
config: { icon: "📘" }
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
},
|
},
|
||||||
|
@ -32,8 +43,10 @@ const json: IJsonModel = {
|
||||||
children: [
|
children: [
|
||||||
{
|
{
|
||||||
type: "tab",
|
type: "tab",
|
||||||
|
id: 'tab2',
|
||||||
name: "Two",
|
name: "Two",
|
||||||
component: "button",
|
component: "tabComponent",
|
||||||
|
config: { icon: "📘" }
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
},
|
},
|
||||||
|
@ -41,22 +54,68 @@ const json: IJsonModel = {
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
const model = Model.fromJson(json);
|
|
||||||
|
|
||||||
const FlexLayoutComponent: React.FC = () => {
|
const FlexLayoutComponent: React.FC = () => {
|
||||||
|
|
||||||
|
const model = Model.fromJson(json);
|
||||||
|
|
||||||
const factory = (node: TabNode) => {
|
const factory = (node: TabNode) => {
|
||||||
const component = node.getComponent();
|
const component = node.getComponent();
|
||||||
|
if (component === "tabComponent") {
|
||||||
if (component === "button") {
|
return <div>{node.getName()}11</div>;
|
||||||
return <button>{node.getName()}</button>;
|
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const renderTab = (node: TabNode, renderValues: ITabRenderValues) => {
|
||||||
|
renderValues.content = (
|
||||||
|
<div style={{ display: "flex", alignItems: "center" }}>
|
||||||
|
<span style={{ marginRight: 5 }}>{node.getConfig().icon}</span>
|
||||||
|
{renderValues.content}
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
const addTab = (node: TabSetNode | BorderNode) => {
|
||||||
|
// 创建一个新的 tab 对象
|
||||||
|
const newTab = {
|
||||||
|
type: "tab",
|
||||||
|
name: "New Tab",
|
||||||
|
component: "tabComponent",
|
||||||
|
config: { icon: '' }
|
||||||
|
};
|
||||||
|
|
||||||
|
// 使用 FlexLayout 的 addAction 执行添加 tab 的动作
|
||||||
|
const addAction = Actions.addNode(newTab, node.getId(), DockLocation.CENTER, -1);
|
||||||
|
node.getModel().doAction(addAction);
|
||||||
|
};
|
||||||
|
|
||||||
|
const onRenderTabSet = (node: TabSetNode | BorderNode, renderValues: ITabSetRenderValues) => {
|
||||||
|
|
||||||
|
const createTabButton = <TooltipProvider>
|
||||||
|
<Tooltip>
|
||||||
|
<TooltipTrigger>
|
||||||
|
<span
|
||||||
|
onClick={() => addTab(node)}
|
||||||
|
key={node.getId() + 'create'}>
|
||||||
|
+</span>
|
||||||
|
</TooltipTrigger>
|
||||||
|
<TooltipContent side="bottom">
|
||||||
|
<p>新建标签页</p>
|
||||||
|
</TooltipContent>
|
||||||
|
</Tooltip>
|
||||||
|
</TooltipProvider>
|
||||||
|
renderValues.stickyButtons.push(createTabButton)
|
||||||
|
};
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Layout
|
<Layout
|
||||||
model={model}
|
model={model}
|
||||||
|
realtimeResize
|
||||||
factory={factory}
|
factory={factory}
|
||||||
classNameMapper={(defaultClass) => `${defaultClass} custom-layout-class`}
|
classNameMapper={(defaultClass) => `${defaultClass} custom-layout-class`}
|
||||||
|
onRenderTab={renderTab}
|
||||||
|
onRenderTabSet={onRenderTabSet}
|
||||||
/>
|
/>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
|
@ -1,9 +1,7 @@
|
||||||
/* Layout.css */
|
/* Layout.css */
|
||||||
|
|
||||||
.custom-layout-class .flexlayout__tab_button {
|
.custom-layout-class .flexlayout__tab_button {
|
||||||
background-color: #4caf50;
|
border-radius: 10px 10px 0 0;
|
||||||
color: white;
|
|
||||||
border-radius: 5px;
|
|
||||||
padding: 5px;
|
padding: 5px;
|
||||||
margin-right: 5px;
|
margin-right: 5px;
|
||||||
cursor: pointer;
|
cursor: pointer;
|
||||||
|
@ -11,4 +9,15 @@
|
||||||
|
|
||||||
.custom-layout-class .flexlayout__tab_button:hover {
|
.custom-layout-class .flexlayout__tab_button:hover {
|
||||||
background-color: #45a049;
|
background-color: #45a049;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* 覆盖默认的 FlexLayout 分割线选中颜色 */
|
||||||
|
.custom-layout-class .flexlayout__splitter_drag {
|
||||||
|
background-color: blue;
|
||||||
|
/* 选中时的颜色 */
|
||||||
|
}
|
||||||
|
|
||||||
|
.custom-layout-class .flexlayout__splitter:hover {
|
||||||
|
background-color: lightblue;
|
||||||
|
/* 鼠标悬停时的颜色 */
|
||||||
}
|
}
|
Loading…
Reference in New Issue
Block a user