Feat(Menu): Add drop mask
Add drop mask to menu. Optimize tool description.
This commit is contained in:
30
src/assets/css/components/dnd/drop-mask.scss
Normal file
30
src/assets/css/components/dnd/drop-mask.scss
Normal file
@@ -0,0 +1,30 @@
|
|||||||
|
@use "@/assets/css/constants" as constants;
|
||||||
|
|
||||||
|
[data-component=component-drop-mask] {
|
||||||
|
position: absolute;
|
||||||
|
left: 0;
|
||||||
|
top: 0;
|
||||||
|
width: 100%;
|
||||||
|
height: 100%;
|
||||||
|
padding: {
|
||||||
|
left: 10px;
|
||||||
|
right: 10px;
|
||||||
|
bottom: 10px;
|
||||||
|
};
|
||||||
|
background-color: constants.$origin-color;
|
||||||
|
|
||||||
|
.drop-mask-border {
|
||||||
|
display: flex;
|
||||||
|
width: 100%;
|
||||||
|
height: 100%;
|
||||||
|
justify-content: center;
|
||||||
|
align-items: center;
|
||||||
|
border: {
|
||||||
|
width: 2px;
|
||||||
|
color: constants.$font-secondary-color;
|
||||||
|
style: dashed;
|
||||||
|
radius: 8px;
|
||||||
|
};
|
||||||
|
font-size: 1.8em;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -23,6 +23,7 @@
|
|||||||
|
|
||||||
.version {
|
.version {
|
||||||
width: 0;
|
width: 0;
|
||||||
|
transition: all 0.2s;
|
||||||
}
|
}
|
||||||
|
|
||||||
.operation {
|
.operation {
|
||||||
@@ -30,6 +31,7 @@
|
|||||||
font-size: 1.6em;
|
font-size: 1.6em;
|
||||||
gap: 4px;
|
gap: 4px;
|
||||||
opacity: 0;
|
opacity: 0;
|
||||||
|
transition: all 0.2s;
|
||||||
|
|
||||||
> *:hover {
|
> *:hover {
|
||||||
color: constants.$font-secondary-color;
|
color: constants.$font-secondary-color;
|
||||||
|
|||||||
@@ -7,6 +7,7 @@
|
|||||||
|
|
||||||
.menu-droppable {
|
.menu-droppable {
|
||||||
display: flex;
|
display: flex;
|
||||||
|
position: relative;
|
||||||
min-height: 0;
|
min-height: 0;
|
||||||
flex: 1;
|
flex: 1;
|
||||||
width: 100%;
|
width: 100%;
|
||||||
|
|||||||
1
src/assets/svg/receive.svg
Normal file
1
src/assets/svg/receive.svg
Normal file
@@ -0,0 +1 @@
|
|||||||
|
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 1024 1024"><path d="M927.929032 640.065509a31.994541 31.994541 0 0 0-31.994541 31.994541v127.978163c0 52.918971-43.064652 95.983623-95.983623 95.983623h-575.901736c-52.918971 0-95.983623-43.064652-95.983623-95.983623v-127.978163a31.994541 31.994541 0 0 0-63.989082 0v127.978163C64.076427 888.279157 135.872177 960.010918 224.049132 960.010918h575.901736c88.240944 0 159.972705-71.731761 159.972705-159.972705v-127.978163a31.994541 31.994541 0 0 0-31.994541-31.994541z" /><path d="M412.113043 777.386079c18.684812 18.684812 43.256619 28.027218 67.892416 28.027217s49.143615-9.342406 67.892416-28.027217l274.705128-274.705129A31.930552 31.930552 0 0 0 799.950868 448.098263h-159.140846a629.524587 629.524587 0 0 1 44.408423-202.909378L765.652721 44.0712a32.122519 32.122519 0 0 0-7.998636-35.449951 32.122519 32.122519 0 0 0-35.961864-5.055137L566.582687 81.120879A443.124392 443.124392 0 0 0 321.184558 448.098263H160.06005a31.994541 31.994541 0 0 0-22.652135 54.646676l274.705128 274.64114zM352.027295 512.023356a31.994541 31.994541 0 0 0 31.994541-31.994541A379.711212 379.711212 0 0 1 595.185806 138.391107l79.858375-39.929187-49.207604 122.923026A692.7458 692.7458 0 0 0 575.989082 480.092804a31.994541 31.994541 0 0 0 31.994541 31.994541h114.732424l-220.058453 220.058453a31.994541 31.994541 0 0 1-45.240281 0L237.294872 512.087345 352.027295 512.023356z" /></svg>
|
||||||
|
After Width: | Height: | Size: 1.4 KiB |
14
src/components/dnd/DropMask.tsx
Normal file
14
src/components/dnd/DropMask.tsx
Normal file
@@ -0,0 +1,14 @@
|
|||||||
|
import '@/assets/css/components/dnd/drop-mask.scss'
|
||||||
|
import Icon from '@ant-design/icons'
|
||||||
|
|
||||||
|
const DropMask = () => {
|
||||||
|
return (
|
||||||
|
<div data-component={'component-drop-mask'}>
|
||||||
|
<div className={'drop-mask-border'}>
|
||||||
|
<Icon component={IconOxygenReceive} />
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
export default DropMask
|
||||||
@@ -4,14 +4,19 @@ import protocolCheck from 'custom-protocol-check'
|
|||||||
import Icon from '@ant-design/icons'
|
import Icon from '@ant-design/icons'
|
||||||
import '@/assets/css/components/tools/store-card.scss'
|
import '@/assets/css/components/tools/store-card.scss'
|
||||||
import { COLOR_BACKGROUND, COLOR_MAIN, COLOR_PRODUCTION } from '@/constants/common.constants'
|
import { COLOR_BACKGROUND, COLOR_MAIN, COLOR_PRODUCTION } from '@/constants/common.constants'
|
||||||
import { checkDesktop } from '@/util/common'
|
import { checkDesktop, omitText } from '@/util/common'
|
||||||
import { navigateToSource, navigateToStore, navigateToView } from '@/util/navigation'
|
import { getLoginStatus, getUserId } from '@/util/auth'
|
||||||
|
import {
|
||||||
|
navigateToLogin,
|
||||||
|
navigateToSource,
|
||||||
|
navigateToStore,
|
||||||
|
navigateToView
|
||||||
|
} from '@/util/navigation'
|
||||||
import { r_tool_add_favorite, r_tool_remove_favorite } from '@/services/tool'
|
import { r_tool_add_favorite, r_tool_remove_favorite } from '@/services/tool'
|
||||||
import Card from '@/components/common/Card'
|
import Card from '@/components/common/Card'
|
||||||
import FlexBox from '@/components/common/FlexBox'
|
import FlexBox from '@/components/common/FlexBox'
|
||||||
import { getUserId } from '@/util/auth.tsx'
|
import DragHandle from '@/components/dnd/DragHandle'
|
||||||
import DragHandle from '@/components/dnd/DragHandle.tsx'
|
import Draggable from '@/components/dnd/Draggable'
|
||||||
import Draggable from '@/components/dnd/Draggable.tsx'
|
|
||||||
|
|
||||||
interface StoreCardProps extends DetailedHTMLProps<HTMLAttributes<HTMLDivElement>, HTMLDivElement> {
|
interface StoreCardProps extends DetailedHTMLProps<HTMLAttributes<HTMLDivElement>, HTMLDivElement> {
|
||||||
icon: string
|
icon: string
|
||||||
@@ -58,7 +63,9 @@ const StoreCard = ({
|
|||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
cardRef.current && VanillaTilt.init(cardRef.current, options)
|
cardRef.current && VanillaTilt.init(cardRef.current, options)
|
||||||
getUserId().then((value) => setUserId(value))
|
if (getLoginStatus()) {
|
||||||
|
void getUserId().then((value) => setUserId(value))
|
||||||
|
}
|
||||||
}, [options])
|
}, [options])
|
||||||
|
|
||||||
const handleCardOnClick = () => {
|
const handleCardOnClick = () => {
|
||||||
@@ -99,6 +106,10 @@ const StoreCard = ({
|
|||||||
|
|
||||||
const handleOnStarBtnClick = (e: MouseEvent<HTMLDivElement>) => {
|
const handleOnStarBtnClick = (e: MouseEvent<HTMLDivElement>) => {
|
||||||
e.stopPropagation()
|
e.stopPropagation()
|
||||||
|
if (!getLoginStatus()) {
|
||||||
|
navigateToLogin(navigate, undefined, `${location.pathname}${location.search}`)
|
||||||
|
return
|
||||||
|
}
|
||||||
if (favorite_) {
|
if (favorite_) {
|
||||||
void r_tool_remove_favorite({
|
void r_tool_remove_favorite({
|
||||||
authorId: author.id,
|
authorId: author.id,
|
||||||
@@ -249,7 +260,12 @@ const StoreCard = ({
|
|||||||
<div className={'info'}>
|
<div className={'info'}>
|
||||||
<div className={'tool-name'}>{toolName}</div>
|
<div className={'tool-name'}>{toolName}</div>
|
||||||
<div className={'tool-id'}>{`ID: ${toolId}`}</div>
|
<div className={'tool-id'}>{`ID: ${toolId}`}</div>
|
||||||
{toolDesc && <div className={'tool-desc'}>{`简介:${toolDesc}`}</div>}
|
{toolDesc && (
|
||||||
|
<div
|
||||||
|
className={'tool-desc'}
|
||||||
|
title={toolDesc}
|
||||||
|
>{`简介:${omitText(toolDesc, 18)}`}</div>
|
||||||
|
)}
|
||||||
</div>
|
</div>
|
||||||
{showAuthor && (
|
{showAuthor && (
|
||||||
<div className={'author'} onClick={handleOnClickAuthor}>
|
<div className={'author'} onClick={handleOnClickAuthor}>
|
||||||
|
|||||||
@@ -1,25 +1,30 @@
|
|||||||
import { DndContext, DragOverEvent, DragStartEvent } from '@dnd-kit/core'
|
import { DndContext, DragOverEvent, DragStartEvent } from '@dnd-kit/core'
|
||||||
import Droppable from '@/components/dnd/Droppable'
|
import { arrayMove, SortableContext } from '@dnd-kit/sortable'
|
||||||
import type { DragEndEvent } from '@dnd-kit/core/dist/types'
|
import type { DragEndEvent } from '@dnd-kit/core/dist/types'
|
||||||
import '@/assets/css/pages/tools-framework.scss'
|
import '@/assets/css/pages/tools-framework.scss'
|
||||||
import { tools } from '@/router/tools'
|
import { tools } from '@/router/tools'
|
||||||
|
import { getToolMenuItem, saveToolMenuItem } from '@/util/common'
|
||||||
|
import { getViewPath } from '@/util/navigation'
|
||||||
import FitFullscreen from '@/components/common/FitFullscreen'
|
import FitFullscreen from '@/components/common/FitFullscreen'
|
||||||
import Sidebar from '@/components/common/Sidebar'
|
import Sidebar from '@/components/common/Sidebar'
|
||||||
import FullscreenLoadingMask from '@/components/common/FullscreenLoadingMask'
|
import FullscreenLoadingMask from '@/components/common/FullscreenLoadingMask'
|
||||||
import { arrayMove, SortableContext } from '@dnd-kit/sortable'
|
import Sortable from '@/components/dnd/Sortable'
|
||||||
import { getViewPath } from '@/util/navigation.tsx'
|
import DragHandle from '@/components/dnd/DragHandle'
|
||||||
import Sortable from '@/components/dnd/Sortable.tsx'
|
import DraggableOverlay from '@/components/dnd/DraggableOverlay'
|
||||||
import DragHandle from '@/components/dnd/DragHandle.tsx'
|
import DropMask from '@/components/dnd/DropMask'
|
||||||
import DraggableOverlay from '@/components/dnd/DraggableOverlay.tsx'
|
import Droppable from '@/components/dnd/Droppable'
|
||||||
import { getToolMenuItem, saveToolMenuItem } from '@/util/common.tsx'
|
|
||||||
|
|
||||||
const ToolsFramework = () => {
|
const ToolsFramework = () => {
|
||||||
const [isDelete, setIsDelete] = useState(false)
|
const [isDelete, setIsDelete] = useState(false)
|
||||||
const [toolMenuItem, setToolMenuItem] = useState<ToolMenuItem[]>(getToolMenuItem)
|
const [toolMenuItem, setToolMenuItem] = useState<ToolMenuItem[]>(getToolMenuItem)
|
||||||
const [activeItem, setActiveItem] = useState<ToolMenuItem | null>(null)
|
const [activeItem, setActiveItem] = useState<ToolMenuItem | null>(null)
|
||||||
|
const [showDropMask, setShowDropMask] = useState(false)
|
||||||
|
|
||||||
const handleOnDragStart = ({ active }: DragStartEvent) => {
|
const handleOnDragStart = ({ active }: DragStartEvent) => {
|
||||||
setActiveItem(active.data.current as ToolMenuItem)
|
setActiveItem(active.data.current as ToolMenuItem)
|
||||||
|
if (!active.data.current?.sortable) {
|
||||||
|
setShowDropMask(true)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const handleOnDragOver = ({ over }: DragOverEvent) => {
|
const handleOnDragOver = ({ over }: DragOverEvent) => {
|
||||||
@@ -62,10 +67,8 @@ const ToolsFramework = () => {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
console.log('active', active)
|
|
||||||
console.log('over', over)
|
|
||||||
|
|
||||||
setActiveItem(null)
|
setActiveItem(null)
|
||||||
|
setShowDropMask(false)
|
||||||
}
|
}
|
||||||
|
|
||||||
const handleOnDragCancel = () => {
|
const handleOnDragCancel = () => {
|
||||||
@@ -164,6 +167,7 @@ const ToolsFramework = () => {
|
|||||||
</DraggableOverlay>
|
</DraggableOverlay>
|
||||||
</Sidebar.ItemList>
|
</Sidebar.ItemList>
|
||||||
</Sidebar.Scroll>
|
</Sidebar.Scroll>
|
||||||
|
{showDropMask && <DropMask />}
|
||||||
</Droppable>
|
</Droppable>
|
||||||
</Sidebar>
|
</Sidebar>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -1,8 +1,8 @@
|
|||||||
import { createRoot } from 'react-dom/client'
|
import { createRoot } from 'react-dom/client'
|
||||||
import FullscreenLoadingMask from '@/components/common/FullscreenLoadingMask'
|
|
||||||
import { floor } from 'lodash'
|
import { floor } from 'lodash'
|
||||||
import { getLocalStorage, setLocalStorage } from '@/util/browser.tsx'
|
import { STORAGE_TOOL_MENU_ITEM_KEY } from '@/constants/common.constants'
|
||||||
import { STORAGE_TOOL_MENU_ITEM_KEY } from '@/constants/common.constants.ts'
|
import { getLocalStorage, setLocalStorage } from '@/util/browser'
|
||||||
|
import FullscreenLoadingMask from '@/components/common/FullscreenLoadingMask'
|
||||||
|
|
||||||
export const randomInt = (start: number, end: number) => {
|
export const randomInt = (start: number, end: number) => {
|
||||||
if (start > end) {
|
if (start > end) {
|
||||||
@@ -147,3 +147,10 @@ export const getToolMenuItem = (): ToolMenuItem[] => {
|
|||||||
}
|
}
|
||||||
return JSON.parse(s) as ToolMenuItem[]
|
return JSON.parse(s) as ToolMenuItem[]
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export const omitText = (text: string, length: number) => {
|
||||||
|
if (text.length <= length) {
|
||||||
|
return text
|
||||||
|
}
|
||||||
|
return `${text.substring(0, length)}...`
|
||||||
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user