diff --git a/.stylelintrc.js b/.stylelintrc.js
index fa95536c1516b40f134db6febda92a232590b0c2..38d55358192140d41c9d90a1eadc44f58b6ca8a3 100644
--- a/.stylelintrc.js
+++ b/.stylelintrc.js
@@ -10,6 +10,12 @@ module.exports = {
rules: {
'no-empty-source': null,
'selector-class-pattern': '^[a-z][a-zA-Z0-9]+$',
+ 'selector-pseudo-class-no-unknown': [
+ true,
+ {
+ ignorePseudoClasses: ['global']
+ }
+ ],
'color-function-notation': 'legacy',
'alpha-value-notation': 'number',
// 属性的排序
diff --git a/package-lock.json b/package-lock.json
index 55bd3e7c5484d941abe3c7dbd733065fed69191d..64e79c1b40e3b338969703126f6e62d574609d74 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -4512,11 +4512,6 @@
"integrity": "sha512-cOU9usZw8/dXIXKtwa8pM0OTJQuJkxMN6w30csNRUerHfeQ5R6U3kkU/FtJeIf3M202OHfY2U8ccInBG7/xogA==",
"dev": true
},
- "classname": {
- "version": "0.0.0",
- "resolved": "https://registry.npmjs.org/classname/-/classname-0.0.0.tgz",
- "integrity": "sha512-kkhsspEJdUW+VhuvNzb2sQf0KbafDPfd36dB1qf03Uu42dWZwMQzaQuyNkaRr5ir0ZiAN0+TlH/EOOfwb/aaXg=="
- },
"classnames": {
"version": "2.3.2",
"resolved": "https://registry.npmjs.org/classnames/-/classnames-2.3.2.tgz",
diff --git a/package.json b/package.json
index c57020e9b9b091b4027f0f662d1eea4558cd6f4b..d689d9abe7ce741eef27535024277bb4f41b6e5f 100644
--- a/package.json
+++ b/package.json
@@ -97,7 +97,7 @@
"@ant-design/icons": "^4.7.0",
"antd": "^4.23.2",
"axios": "^0.27.2",
- "classname": "0.0.0",
+ "classnames": "^2.3.2",
"lodash": "^4.17.21",
"react-router-dom": "^6.4.0",
"zustand": "^4.1.1"
diff --git a/src/common/constants/index.ts b/src/common/constants/index.ts
new file mode 100644
index 0000000000000000000000000000000000000000..3778d6404552fb1eef29a89952c2e4b8b8a5fc09
--- /dev/null
+++ b/src/common/constants/index.ts
@@ -0,0 +1,8 @@
+// 窗口状态常量
+const WINDOW_STATUS = {
+ NORMAL: 0, // 正常
+ MIN: 1, // 最小化
+ MAX: 2 // 最大化
+}
+
+export { WINDOW_STATUS }
diff --git a/src/common/style/vars.scss b/src/common/style/vars.scss
index 5de36de16195a2e55b7ed8164715890a9fb1f6fc..ba6a337b294765c8c744ff696022ba31e5ffde56 100644
--- a/src/common/style/vars.scss
+++ b/src/common/style/vars.scss
@@ -5,10 +5,19 @@ $desk-background2: rgba(255, 255, 255, 0.1);
$hover-background1: rgba(255, 255, 255, 0.25);
+$window-border-color: #555;
+$window-header-height: 32px;
+$window-background: #303030;
+
$border-color1: #eee;
$scrollbar-thumb1: #999;
+$start-tools-bar-height: 48px;
+
$start-menu-width: 600px;
$start-menu-height: 550px;
+:export {
+ startToolsBarHeight: $start-tools-bar-height
+}
diff --git a/src/common/utils/getId.ts b/src/common/utils/getId.ts
new file mode 100644
index 0000000000000000000000000000000000000000..68e50aecbe5f31c22e3915621c8c24aab3681879
--- /dev/null
+++ b/src/common/utils/getId.ts
@@ -0,0 +1,9 @@
+import { customAlphabet } from 'nanoid'
+
+const getId = (size = 32) => {
+ const dictionary =
+ '0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz'
+ return customAlphabet(dictionary, size)
+}
+
+export default getId()
diff --git a/src/pages/Desktop/StartToolsBar/index.module.scss b/src/pages/Desktop/StartToolsBar/index.module.scss
index 5c41d66b31c252e35b24788e573eee1511c291b2..48c89fd39dd5e72d26715144bdcf0a20ff46cedd 100644
--- a/src/pages/Desktop/StartToolsBar/index.module.scss
+++ b/src/pages/Desktop/StartToolsBar/index.module.scss
@@ -4,7 +4,7 @@
left: 0;
z-index: 9999;
width: 100%;
- height: 48px;
+ height: $start-tools-bar-height;
background: $desk-background1;
backdrop-filter: saturate(3) blur(20px);
}
diff --git a/src/pages/Desktop/Window/WindowBox/Header/index.module.scss b/src/pages/Desktop/Window/WindowBox/Header/index.module.scss
new file mode 100644
index 0000000000000000000000000000000000000000..65bdcb804ddc5ddb1048cf224b211383bf7f187c
--- /dev/null
+++ b/src/pages/Desktop/Window/WindowBox/Header/index.module.scss
@@ -0,0 +1,55 @@
+.headerBox {
+ display: flex;
+ flex-direction: row;
+ border-bottom: 1px solid $window-border-color;
+ width: 100%;
+ height: $window-header-height;
+}
+
+.title {
+ flex-grow: 1;
+ line-height: 30px;
+ padding-left: 15px;
+ font-size: 12px;
+ user-select: none;
+ cursor: all-scroll;
+}
+
+.tools {
+ display: flex;
+ flex-direction: row;
+}
+
+.tool {
+ display: flex;
+ justify-content: center;
+ align-items: center;
+ width: 46px;
+ cursor: pointer;
+
+ &:hover {
+ background-color: $desk-background2;
+ }
+}
+
+.full {
+ :global {
+ svg {
+ font-size: 11px;
+ }
+ }
+}
+
+.normal {
+ :global {
+ svg {
+ font-size: 13px;
+ }
+ }
+}
+
+.close {
+ &:hover {
+ background-color: rgb(232, 17, 35) !important;
+ }
+}
diff --git a/src/pages/Desktop/Window/WindowBox/Header/index.tsx b/src/pages/Desktop/Window/WindowBox/Header/index.tsx
new file mode 100644
index 0000000000000000000000000000000000000000..5a9959274e5da64e1ce674c053f4ea57bccbaa87
--- /dev/null
+++ b/src/pages/Desktop/Window/WindowBox/Header/index.tsx
@@ -0,0 +1,51 @@
+import React from 'react'
+import {
+ MinusOutlined,
+ CloseOutlined,
+ BorderOutlined,
+ BlockOutlined
+} from '@ant-design/icons'
+import classnames from 'classnames'
+import styles from './index.module.scss'
+import WindowContext from '@/pages/Desktop/Window/WindowContext'
+import useStore, { MyState } from '@/store'
+import { WINDOW_STATUS } from '@/common/constants'
+
+const Header: React.FC = () => {
+ const { window, id: windowId } = React.useContext(WindowContext)
+ const editWindowStatus = useStore((state: MyState) => state.setWindowStatus)
+ const closeWindow = useStore((state: MyState) => state.closeWindow)
+ return (
+
+
{window.title}
+
+
editWindowStatus(WINDOW_STATUS.MIN, windowId)}>
+
+
+ {window.status === WINDOW_STATUS.NORMAL && (
+
editWindowStatus(WINDOW_STATUS.MAX, windowId)}>
+
+
+ )}
+ {window.status === WINDOW_STATUS.MAX && (
+
editWindowStatus(WINDOW_STATUS.NORMAL, windowId)}>
+
+
+ )}
+
closeWindow(windowId)}>
+
+
+
+
+ )
+}
+
+export default Header
diff --git a/src/pages/Desktop/Window/WindowBox/index.module.scss b/src/pages/Desktop/Window/WindowBox/index.module.scss
new file mode 100644
index 0000000000000000000000000000000000000000..193b38b97cff8ec8ac1e65244c9da47c405bb3e7
--- /dev/null
+++ b/src/pages/Desktop/Window/WindowBox/index.module.scss
@@ -0,0 +1,47 @@
+$drag: 8px;
+$shift: -6px;
+
+.windowBox {
+ position: absolute;
+ border: 1px solid $window-border-color;
+ border-radius: 3px;
+ background-color: $window-background;
+}
+
+.main {
+ position: relative;
+ width: 100%;
+ height: 100%;
+}
+
+.content {
+ width: 100%;
+ height: calc(100% - #{$window-header-height});
+}
+
+.dragRight {
+ position: absolute;
+ top: 32px;
+ right: $shift;
+ width: $drag;
+ height: calc(100% - #{$drag + $shift} - 32px);
+ cursor: e-resize;
+}
+
+.dragBottom {
+ position: absolute;
+ bottom: $shift;
+ left: 0;
+ width: calc(100% - #{$drag + $shift});
+ height: $drag;
+ cursor: s-resize;
+}
+
+.dragRightBottom {
+ position: absolute;
+ right: $shift;
+ bottom: $shift;
+ width: $drag;
+ height: $drag;
+ cursor: se-resize;
+}
diff --git a/src/pages/Desktop/Window/WindowBox/index.tsx b/src/pages/Desktop/Window/WindowBox/index.tsx
new file mode 100644
index 0000000000000000000000000000000000000000..2c601187d03f2d91352f180f4c715abf223f899a
--- /dev/null
+++ b/src/pages/Desktop/Window/WindowBox/index.tsx
@@ -0,0 +1,40 @@
+import React from 'react'
+import WindowContext from '../WindowContext'
+import styles from './index.module.scss'
+import Header from './Header'
+import { WINDOW_STATUS } from '@/common/constants'
+import vars from '@/common/style/vars.scss'
+
+interface Props {
+ children: React.ReactNode
+}
+
+const WindowBox: React.FC = props => {
+ const { window } = React.useContext(WindowContext)
+ const windowStyle = React.useMemo(() => {
+ const cssStyle = { ...window.style }
+ if (window.status === WINDOW_STATUS.MAX) {
+ cssStyle.left = 0
+ cssStyle.top = 0
+ cssStyle.width = '100%'
+ cssStyle.height = `calc(100% - ${vars.startToolsBarHeight})`
+ }
+ if (window.status === WINDOW_STATUS.MIN) {
+ cssStyle.display = 'none'
+ }
+ return cssStyle
+ }, [window.style, window.status])
+ return (
+
+
+
+
{props.children}
+
+
+
+
+
+ )
+}
+
+export default WindowBox
diff --git a/src/pages/Desktop/Window/WindowContext.ts b/src/pages/Desktop/Window/WindowContext.ts
new file mode 100644
index 0000000000000000000000000000000000000000..9b68e1b2d740f3d22bbeab712efd92890c6b8fc6
--- /dev/null
+++ b/src/pages/Desktop/Window/WindowContext.ts
@@ -0,0 +1,14 @@
+import React from 'react'
+import type { Window } from '@/store/windowSlice'
+
+export interface WindowContextType {
+ window: Window
+ id: string
+ index: number
+}
+
+export default React.createContext({
+ window: {} as Window,
+ id: '',
+ index: 0
+})
diff --git a/src/pages/Desktop/Window/index.module.scss b/src/pages/Desktop/Window/index.module.scss
new file mode 100644
index 0000000000000000000000000000000000000000..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391
diff --git a/src/pages/Desktop/Window/index.tsx b/src/pages/Desktop/Window/index.tsx
new file mode 100644
index 0000000000000000000000000000000000000000..ca982399e3c3f966496d680492d25c1527251390
--- /dev/null
+++ b/src/pages/Desktop/Window/index.tsx
@@ -0,0 +1,35 @@
+import React from 'react'
+import styles from './index.module.scss'
+import WindowContext from './WindowContext'
+import type { Window as WindowType } from '@/store/windowSlice'
+import WindowBox from './WindowBox'
+
+interface Props {
+ window: WindowType
+ index: number
+}
+
+const Window: React.FC = () => {
+ const { window } = React.useContext(WindowContext)
+ return (
+
+
+
+ )
+}
+
+const WindowWithContext: React.FC = props => {
+ const { window, index } = props
+ return (
+
+
+
+ )
+}
+
+export default WindowWithContext
diff --git a/src/pages/Desktop/index.module.scss b/src/pages/Desktop/index.module.scss
index 67d5478030b04c13d7839c44077023f691893312..b821bc8262ea9e218818948a47f1cc03fd5ac180 100644
--- a/src/pages/Desktop/index.module.scss
+++ b/src/pages/Desktop/index.module.scss
@@ -2,4 +2,5 @@
position: relative;
width: 100%;
height: 100%;
+ overflow: hidden;
}
diff --git a/src/pages/Desktop/index.tsx b/src/pages/Desktop/index.tsx
index 5f44cb22cb240fb754b1325e12f1c3d2bb110563..a5ded9cda9f6e9d7c45c2f8a626a8d5a20ee98c3 100644
--- a/src/pages/Desktop/index.tsx
+++ b/src/pages/Desktop/index.tsx
@@ -5,12 +5,17 @@ import StartToolsBar from './StartToolsBar'
import styles from './index.module.scss'
import StartMenu from './StartMenu'
import Mask from './Mask'
+import Window from '@/pages/Desktop/Window'
const Desktop: React.FC = () => {
const showStartMenu = useStore((state: MyState) => state.showStartMenu)
+ const windowList = useStore((state: MyState) => state.windowList)
return (
+ {windowList.map((window, index) => (
+
+ ))}
{showStartMenu && }
{showStartMenu && }
diff --git a/src/react-app-env.d.ts b/src/react-app-env.d.ts
index 9a973e4a160258cf77610087f1d095cf13f6f591..3d255405555247d86a1c57899beed75b5bad1676 100644
--- a/src/react-app-env.d.ts
+++ b/src/react-app-env.d.ts
@@ -60,6 +60,11 @@ declare module '*.module.css' {
export default classes
}
+declare module '*.scss' {
+ const classes: { readonly [key: string]: string }
+ export default classes
+}
+
declare module '*.module.scss' {
const classes: { readonly [key: string]: string }
export default classes
diff --git a/src/store/windowSlice.ts b/src/store/windowSlice.ts
index 3b371086c891df4295e976ac9102497edec152cf..35de82b75510db427399e290f91afd82f2566bc3 100644
--- a/src/store/windowSlice.ts
+++ b/src/store/windowSlice.ts
@@ -1,11 +1,33 @@
import { StoreApi } from 'zustand'
import { MyState } from './index'
import _ from 'lodash'
+import getId from '@utils/getId'
+
+const win = {
+ id: getId(),
+ title: '窗口标题名称',
+ status: 0,
+ style: {
+ display: 'block',
+ width: 800,
+ height: 800,
+ top: 200,
+ left: 100,
+ zIndex: 1
+ }
+}
export interface Window {
id: string
- width: number
- height: number
+ title: string
+ status: number
+ style: WindowStyle
+}
+
+export interface WindowStyle {
+ display: string
+ width: number | string
+ height: number | string
top: number
left: number
zIndex: number
@@ -14,7 +36,9 @@ export interface Window {
export interface WindowSlice {
windowList: Window[]
setWindowList: (windowList: Window[]) => void
- editWindow: (window: Window, index: number) => void
+ editWindow: (window: Window, id: string) => void
+ setWindowStatus: (status: number, id: string) => void
+ closeWindow: (id: string) => void
closeWindowAll: () => void
}
@@ -22,16 +46,38 @@ const windowListSlice = (
set: StoreApi['setState'],
get: StoreApi['getState']
) => ({
- windowList: [], // 窗口列表
+ windowList: [win], // 窗口列表
setWindowList: (windowList: Window[]) => {
// 设置窗口列表
set(prev => ({ windowList: windowList }))
},
- editWindow: (window: Window, index: number) => {
+ editWindow: (window: Window, id: string) => {
// 窗口属性编辑
set(({ windowList }) => {
const list = _.cloneDeep(windowList)
- list[index] = window
+ const windowIndex = list.findIndex(row => row.id === id)
+ list[windowIndex] = window
+ return {
+ windowList: list
+ }
+ })
+ },
+ setWindowStatus: (status: number, id: string) => {
+ set(({ windowList }) => {
+ const list = _.cloneDeep(windowList)
+ const windowIndex = list.findIndex(row => row.id === id)
+ const window = list[windowIndex]
+ window.status = status
+ return {
+ windowList: list
+ }
+ })
+ },
+ closeWindow: (id: string) => {
+ set(({ windowList }) => {
+ const list = _.cloneDeep(windowList)
+ const windowIndex = list.findIndex(row => row.id === id)
+ list.splice(windowIndex, 1)
return {
windowList: list
}