feat: 布局

This commit is contained in:
mozzie 2024-07-17 16:00:35 +08:00
parent c0ab592944
commit d9e8ff195c
6 changed files with 109 additions and 54 deletions

View File

@ -16,6 +16,7 @@
"@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", "@radix-ui/react-tooltip": "^1.1.2",
"@types/react-icons": "^3.0.0",
"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",
@ -27,6 +28,7 @@
"react-day-picker": "^8.10.1", "react-day-picker": "^8.10.1",
"react-desktop": "^0.3.9", "react-desktop": "^0.3.9",
"react-dom": "^18.2.0", "react-dom": "^18.2.0",
"react-icons": "^5.2.1",
"react-resizable-panels": "^2.0.20", "react-resizable-panels": "^2.0.20",
"tailwind-merge": "^2.4.0", "tailwind-merge": "^2.4.0",
"tailwindcss-animate": "^1.0.7" "tailwindcss-animate": "^1.0.7"

View File

@ -23,6 +23,9 @@ importers:
'@radix-ui/react-tooltip': '@radix-ui/react-tooltip':
specifier: ^1.1.2 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) 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)
'@types/react-icons':
specifier: ^3.0.0
version: 3.0.0(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
@ -56,6 +59,9 @@ importers:
react-dom: react-dom:
specifier: ^18.2.0 specifier: ^18.2.0
version: 18.3.1(react@18.3.1) version: 18.3.1(react@18.3.1)
react-icons:
specifier: ^5.2.1
version: 5.2.1(react@18.3.1)
react-resizable-panels: react-resizable-panels:
specifier: ^2.0.20 specifier: ^2.0.20
version: 2.0.20(react-dom@18.3.1(react@18.3.1))(react@18.3.1) version: 2.0.20(react-dom@18.3.1(react@18.3.1))(react@18.3.1)
@ -1110,6 +1116,10 @@ packages:
'@types/react-dom@18.3.0': '@types/react-dom@18.3.0':
resolution: {integrity: sha512-EhwApuTmMBmXuFOikhQLIBUn6uFg81SwLMOAUgodJF14SOBOCMdU04gDoYi0WOJJHD144TL32z4yDqCW3dnkQg==} resolution: {integrity: sha512-EhwApuTmMBmXuFOikhQLIBUn6uFg81SwLMOAUgodJF14SOBOCMdU04gDoYi0WOJJHD144TL32z4yDqCW3dnkQg==}
'@types/react-icons@3.0.0':
resolution: {integrity: sha512-Vefs6LkLqF61vfV7AiAqls+vpR94q67gunhMueDznG+msAkrYgRxl7gYjNem/kZ+as2l2mNChmF1jRZzzQQtMg==}
deprecated: This is a stub types definition. react-icons provides its own type definitions, so you do not need this installed.
'@types/react@18.3.3': '@types/react@18.3.3':
resolution: {integrity: sha512-hti/R0pS0q1/xx+TsI73XIqk26eBsISZ2R0wUijXIngRK9R/e7Xw/cXVxQK7R5JjW+SV4zGcn5hXjudkN/pLIw==} resolution: {integrity: sha512-hti/R0pS0q1/xx+TsI73XIqk26eBsISZ2R0wUijXIngRK9R/e7Xw/cXVxQK7R5JjW+SV4zGcn5hXjudkN/pLIw==}
@ -2403,6 +2413,11 @@ packages:
peerDependencies: peerDependencies:
react: ^18.3.1 react: ^18.3.1
react-icons@5.2.1:
resolution: {integrity: sha512-zdbW5GstTzXaVKvGSyTaBalt7HSfuK5ovrzlpyiWHAFXndXTdd/1hdDHI4xBM1Mn7YriT6aqESucFl9kEXzrdw==}
peerDependencies:
react: '*'
react-is@16.13.1: react-is@16.13.1:
resolution: {integrity: sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ==} resolution: {integrity: sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ==}
@ -3852,6 +3867,12 @@ snapshots:
dependencies: dependencies:
'@types/react': 18.3.3 '@types/react': 18.3.3
'@types/react-icons@3.0.0(react@18.3.1)':
dependencies:
react-icons: 5.2.1(react@18.3.1)
transitivePeerDependencies:
- react
'@types/react@18.3.3': '@types/react@18.3.3':
dependencies: dependencies:
'@types/prop-types': 15.7.12 '@types/prop-types': 15.7.12
@ -4011,7 +4032,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))(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(dmg-builder@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
@ -4025,7 +4046,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(electron-builder-squirrel-windows@24.13.3(dmg-builder@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
@ -4397,9 +4418,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(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))(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(dmg-builder@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
@ -4439,7 +4460,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))(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(dmg-builder@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
@ -4449,11 +4470,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))(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(dmg-builder@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(electron-builder-squirrel-windows@24.13.3(dmg-builder@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
@ -5281,6 +5302,10 @@ snapshots:
react: 18.3.1 react: 18.3.1
scheduler: 0.23.2 scheduler: 0.23.2
react-icons@5.2.1(react@18.3.1):
dependencies:
react: 18.3.1
react-is@16.13.1: {} react-is@16.13.1: {}
react-refresh@0.14.2: {} react-refresh@0.14.2: {}

View File

@ -1,23 +1,43 @@
import React from "react"; import React from "react";
import { Actions, BorderNode, DockLocation, IJsonModel, ITabRenderValues, ITabSetRenderValues, Layout, Model, TabNode, TabSetNode } 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 { Button } from "@/components/ui/button";
import { import {
Tooltip, Tooltip,
TooltipContent, TooltipContent,
TooltipProvider, TooltipProvider,
TooltipTrigger, TooltipTrigger,
} from "@/components/ui/tooltip" } from "@/components/ui/tooltip";
import { VscAdd } from "react-icons/vsc";
const json: IJsonModel = { const json: IJsonModel = {
global: { global: {
tabEnableFloat: false, tabEnableFloat: false,
tabSetMinWidth: 100, tabSetMinWidth: 150,
tabSetMinHeight: 200, tabSetMinHeight: 200,
tabSetTabStripHeight: 48,//tab栏高度 /**
*
*/
tabSetTabStripHeight: 32, //tab栏高度
/**
*
*/
enableEdgeDock: false,
borderMinSize: 100, borderMinSize: 100,
splitterSize: 2, splitterSize: 2,
tabSetClassNameTabStrip: "custom-tab-strip",
}, },
borders: [], borders: [],
layout: { layout: {
@ -30,10 +50,10 @@ const json: IJsonModel = {
children: [ children: [
{ {
type: "tab", type: "tab",
id: 'tab1', id: "tab1",
name: "One", name: "测试22222222222",
component: "tabComponent", component: "tabComponent",
config: { icon: "📘" } config: { icon: "📘" },
}, },
], ],
}, },
@ -43,10 +63,10 @@ const json: IJsonModel = {
children: [ children: [
{ {
type: "tab", type: "tab",
id: 'tab2', id: "tab2",
name: "Two", name: "Two",
component: "tabComponent", component: "tabComponent",
config: { icon: "📘" } config: { icon: "📘" },
}, },
], ],
}, },
@ -54,10 +74,7 @@ const json: IJsonModel = {
}, },
}; };
const FlexLayoutComponent: React.FC = () => { const FlexLayoutComponent: React.FC = () => {
const model = Model.fromJson(json); const model = Model.fromJson(json);
const factory = (node: TabNode) => { const factory = (node: TabNode) => {
@ -69,8 +86,8 @@ const FlexLayoutComponent: React.FC = () => {
const renderTab = (node: TabNode, renderValues: ITabRenderValues) => { const renderTab = (node: TabNode, renderValues: ITabRenderValues) => {
renderValues.content = ( renderValues.content = (
<div style={{ display: "flex", alignItems: "center" }}> <div className="text-xs">
<span style={{ marginRight: 5 }}>{node.getConfig().icon}</span> <span>{node.getConfig().icon}</span>
{renderValues.content} {renderValues.content}
</div> </div>
); );
@ -82,30 +99,41 @@ const FlexLayoutComponent: React.FC = () => {
type: "tab", type: "tab",
name: "New Tab", name: "New Tab",
component: "tabComponent", component: "tabComponent",
config: { icon: '' } config: { icon: "" },
}; };
// 使用 FlexLayout 的 addAction 执行添加 tab 的动作 // 使用 FlexLayout 的 addAction 执行添加 tab 的动作
const addAction = Actions.addNode(newTab, node.getId(), DockLocation.CENTER, -1); const addAction = Actions.addNode(
newTab,
node.getId(),
DockLocation.CENTER,
-1
);
node.getModel().doAction(addAction); node.getModel().doAction(addAction);
}; };
const onRenderTabSet = (node: TabSetNode | BorderNode, renderValues: ITabSetRenderValues) => { const onRenderTabSet = (
node: TabSetNode | BorderNode,
const createTabButton = <TooltipProvider> renderValues: ITabSetRenderValues
<Tooltip> ) => {
<TooltipTrigger> const createTabButton = (
<span <TooltipProvider key={node.getId() + "create"}>
onClick={() => addTab(node)} <Tooltip>
key={node.getId() + 'create'}> <TooltipTrigger asChild>
+</span> <button
</TooltipTrigger> className="inline-flex items-center justify-center whitespace-nowrap rounded-md text-sm font-medium transition-colors focus-visible:outline-none focus-visible:ring-1 focus-visible:ring-ring disabled:pointer-events-none disabled:opacity-50 hover:bg-accent hover:text-accent-foreground h-6 w-6"
<TooltipContent side="bottom"> onClick={() => addTab(node)}
<p></p> >
</TooltipContent> <VscAdd />
</Tooltip> </button>
</TooltipProvider> </TooltipTrigger>
renderValues.stickyButtons.push(createTabButton) <TooltipContent side="bottom">
<p></p>
</TooltipContent>
</Tooltip>
</TooltipProvider>
);
renderValues.stickyButtons.push(createTabButton);
}; };
return ( return (

View File

@ -1,14 +1,6 @@
/* Layout.css */ /* Layout.css */
.custom-tab-strip{
.custom-layout-class .flexlayout__tab_button { border-bottom-color: hsl(var(--border));
border-radius: 10px 10px 0 0;
padding: 5px;
margin-right: 5px;
cursor: pointer;
}
.custom-layout-class .flexlayout__tab_button:hover {
background-color: #45a049;
} }
/* 覆盖默认的 FlexLayout 分割线选中颜色 */ /* 覆盖默认的 FlexLayout 分割线选中颜色 */

View File

@ -1,17 +1,25 @@
import { Button } from "@/components/ui/button";
import { CommandDialogDemo } from "./CommandDialogDemo"; import { CommandDialogDemo } from "./CommandDialogDemo";
import FlexLayoutComponent from "./FlexLayoutDemo"; import FlexLayoutComponent from "./FlexLayoutDemo";
import { VscLayoutSidebarLeftOff } from "react-icons/vsc";
const LayoutMain = () => { const LayoutMain = () => {
return ( return (
<div className="h-screen items-center"> <div className="h-screen">
{/* 此处height和 new BrowserWindow的titleBar设置一致 */} {/* 此处height和 new BrowserWindow的titleBar设置一致 */}
<div <div
className="drag bg-slate-50 px-20 flex items-center" className="drag bg px-20 flex items-center justify-between"
style={{ height: 36 }} style={{ height: 36 }}
> >
<div className="no-drag w-screen inline-flex"> <div className="left">1</div>
<div className="no-drag inline-flex">
<CommandDialogDemo /> <CommandDialogDemo />
</div> </div>
<div className="right no-drag">
<button className="inline-flex items-center justify-center whitespace-nowrap rounded-md text-sm font-medium transition-colors focus-visible:outline-none focus-visible:ring-1 focus-visible:ring-ring disabled:pointer-events-none disabled:opacity-50 hover:bg-accent hover:text-accent-foreground h-6 w-6">
<VscLayoutSidebarLeftOff />
</button>
</div>
</div> </div>
<div className="h-[calc(100%-36px)] relative"> <div className="h-[calc(100%-36px)] relative">
<FlexLayoutComponent /> <FlexLayoutComponent />

View File

@ -11,7 +11,7 @@ body,
@layer base { @layer base {
:root { :root {
--background: 0 0% 100%; --background: 0 0% 97.25%;
--foreground: 240 10% 3.9%; --foreground: 240 10% 3.9%;
--card: 0 0% 100%; --card: 0 0% 100%;
--card-foreground: 240 10% 3.9%; --card-foreground: 240 10% 3.9%;