From f1288e6039765fc7943d10128d1eca0302902d39 Mon Sep 17 00:00:00 2001 From: hwr <763230412@qq.com> Date: Tue, 15 Aug 2023 13:39:28 +0800 Subject: [PATCH] feat: implement LocalStorage,SetDefault,DeleteCollection,AddCurRepo feature --- .../features/repo-collection/view.tsx | 242 +++++++++++++++--- 1 file changed, 208 insertions(+), 34 deletions(-) diff --git a/src/pages/ContentScripts/features/repo-collection/view.tsx b/src/pages/ContentScripts/features/repo-collection/view.tsx index 28d40c07..300e27d3 100644 --- a/src/pages/ContentScripts/features/repo-collection/view.tsx +++ b/src/pages/ContentScripts/features/repo-collection/view.tsx @@ -1,4 +1,4 @@ -import React, { useState } from 'react'; +import React, { useEffect, useState } from 'react'; import { DownOutlined } from '@ant-design/icons'; import { Dropdown, Space, Divider, Button, Input, theme } from 'antd'; import type { MenuProps } from 'antd'; @@ -7,7 +7,17 @@ import { GithubOutlined, SettingOutlined, DeleteOutlined, + FolderAddOutlined, } from '@ant-design/icons'; +import { getRepoName } from '../../../../helpers/get-repo-info'; + +const iconMap: any = { + AppstoreOutlined: AppstoreOutlined, + GithubOutlined: GithubOutlined, + SettingOutlined: SettingOutlined, + DeleteOutlined: DeleteOutlined, + FolderAddOutlined: FolderAddOutlined, +}; const { useToken } = theme; @@ -33,50 +43,152 @@ function getItem( const View = () => { const { token } = useToken(); - const contentStyle: React.CSSProperties = { backgroundColor: token.colorBgElevated, borderRadius: token.borderRadiusLG, boxShadow: token.boxShadowSecondary, }; - const menuStyle: React.CSSProperties = { boxShadow: 'none', }; - - const [items, setitems] = useState([ + const DefaultItems = [ getItem('X-Lab', 'collection1', , [ getItem('delete collection', 'delete1', ), + getItem('add current Repo', 'add1', ), { type: 'divider' }, - getItem('open-digger', '1'), - getItem('open-perf', '2'), - getItem('open-leaderboard', '3'), - getItem('open-wonderland', '4'), + getItem('open-digger', '1.1'), + getItem('open-perf', '1.2'), + getItem('open-leaderboard', '1.3'), + getItem('open-wonderland', '1.4'), ]), - getItem('Collection Two', 'collection2', , [ + getItem('Hypertrons', 'collection2', , [ getItem('delete collection', 'delete2', ), + getItem('add current Repo', 'add2', ), { type: 'divider' }, - getItem('Option 5', '5'), - getItem('Option 6', '6'), + getItem('hypertrons-crx', '2.1'), + getItem('hypertrons-crx-website', '2.2'), ]), getItem('Collection Three', 'collection3', , [ getItem('delete collection', 'delete3', ), + getItem('add current Repo', 'add3', ), { type: 'divider' }, - getItem('Option 9', '9'), - getItem('Option 10', '10'), - getItem('Option 11', '11'), - getItem('Option 12', '12'), + getItem('Option 9', '3.1'), + getItem('Option 10', '3.2'), + getItem('Option 11', '3.3'), + getItem('Option 12', '3.4'), ]), - ]); - + ]; + const [items, setitems] = useState(DefaultItems); + const [refresh, setRefresh] = useState(0); const [newCollectionName, setNewCollectionName] = useState(''); + const [open, setOpen] = useState(false); + + //将 Repo Collection 信息转化为 `JSON` 用于存至 Chrome 本地 + const StorageCollection = (Storage: any) => { + const jsonArray = Storage.map((item: any) => { + const childrenArray = item.children + ? item.children.map((child: any) => { + if (child.type === 'divider') { + return { type: 'divider' }; + } + return { + label: child.label, + key: child.key, + icon: child.icon && child.icon.type.render.displayName, + }; + }) + : undefined; + + return { + label: item.label, + key: item.key, + icon: item.icon && item.icon.type.render.displayName, + children: childrenArray, + }; + }); + + chrome.storage.local.set({ UserCollection: jsonArray }).then(() => { + console.log('UserCollection is set'); + }); + }; + + //每次对 Repo Collection 列表更新后,执行 UpdateCollection 更新 Key值 + const UpdateCollection = (updatedItems: any) => { + const renumberedItems = updatedItems.map((collection: any, index: any) => { + return { + ...collection, + key: `collection${index + 1}`, + children: collection.children.map((child: any) => { + if (/^delete/.test(child.key)) { + return { + ...child, + key: `delete${index + 1}`, + }; + } else if (/^add/.test(child.key)) { + return { + ...child, + key: `add${index + 1}`, + }; + } else if (child.type === 'divider') { + return { ...child }; + } else { + const childIndex = parseInt(child.key.split('.')[1]); + return { + ...child, + key: `${index + 1}.${childIndex}`, + }; + } + }), + }; + }); + + console.log(renumberedItems); + + setitems(renumberedItems); + + // 更新本地存储 + StorageCollection(renumberedItems); + }; + + // 将 JSON 转化为 Item 初始化的数据结构 + const ConvertJSONToItem = (jsonArray: any) => { + return jsonArray.map((item: any) => { + const children = item.children.map((child: any) => { + if (child.type === 'divider') { + return { type: 'divider' }; + } + + const childIconComponent = child.icon + ? React.createElement(iconMap[child.icon]) + : undefined; + + return getItem(child.label, child.key, childIconComponent); + }); + + const iconComponent = item.icon + ? React.createElement(iconMap[item.icon]) + : undefined; + + return getItem(item.label, item.key, iconComponent, children); + }); + }; + + // 读取用户自定义的 Repo Collection + useEffect(() => { + chrome.storage.local.get(['UserCollection']).then((result) => { + if (result.UserCollection) { + const CollectionArray: any = ConvertJSONToItem(result.UserCollection); + setitems(CollectionArray); + } + }); + }, [refresh]); const AddRepoCollection = () => { if (newCollectionName.trim() === '') { alert('请输入集合名称'); return; } - alert(newCollectionName); + // 找到所有 collection 编号的最大值 const collectionNumbers = items.map((item: any) => { const match = item.key.match(/collection(\d+)/); @@ -99,44 +211,105 @@ const View = () => { `delete${newCollectionNumber}`, ), + getItem( + 'add current Repo', + `add${newCollectionNumber}`, + + ), { type: 'divider' }, ] ); // 更新 items 数组 setitems([...items, newMenuItem]); + + // 更新本地存储,需要转化为JSON格式 + StorageCollection([...items, newMenuItem]); + }; + + const SetAsDefault = () => { + setitems(DefaultItems); + StorageCollection(DefaultItems); }; - const DeleteRepoCollection = (info: any) => { - const clickedItemKey = info.keyPath; + const handleMenuClick: MenuProps['onClick'] = (info) => { + const clickedItemKey: any = info.keyPath; + // Check if the clicked item is the "delete collection" label if (/^delete/.test(clickedItemKey[0])) { - const updatedItems = items.filter( + const updatedItems: any = items.filter( (item: any) => item.key !== clickedItemKey[1] ); - setitems(updatedItems); // 重新分配集合的键值 - const renumberedItems = updatedItems.map((item: any, index) => { - const match = item.key.match(/collection(\d+)/); - const newCollectionNumber = index + 1; - return { - ...item, - key: match ? `collection${newCollectionNumber}` : item.key, - }; - }); + UpdateCollection(updatedItems); + } + + // Check if the clicked item is the "add current Repo" label + if (/^add/.test(clickedItemKey[0])) { + const RepoFullName = getRepoName(); + const RepoName = RepoFullName.match(/\/([^/]+)$/); + + if (RepoName) { + const CollectionNumber = clickedItemKey[1].match(/\d+/)[0]; + const targetCollection: any = items.find( + (item: any) => item.key === clickedItemKey[1] + ); + + if ( + targetCollection.children.some( + (item: any) => item.label === RepoName[1] + ) + ) { + alert('该仓库已存在~'); + return; + } + const pattern = new RegExp(`^${CollectionNumber}\.(\\d+)`); + const matchingNumbers = targetCollection.children + .filter((item: any) => pattern.test(item.key)) + .map((item: any) => parseInt(item.key.match(pattern)[1])); + const maxNumber = Math.max(...matchingNumbers); + + // 创建新的 Repo 编号 + const newRepoKey = maxNumber + 1; + + const newRepoLabel = RepoName[1]; - setitems(renumberedItems); + // 创建新的 Repo项 + const newRepoItem = getItem( + newRepoLabel, + `${CollectionNumber}.${newRepoKey}` + ); + targetCollection.children.push(newRepoItem); + } + + // 更新 items 数组 + setitems(items); + + UpdateCollection(items); + + setRefresh(refresh + 1); } }; + const handleOpenChange = (newOpen: boolean) => { + setOpen(newOpen); + }; + return (
(
@@ -148,6 +321,7 @@ const View = () => { onChange={(e) => setNewCollectionName(e.target.value)} /> + {React.cloneElement(menu as React.ReactElement, { @@ -159,7 +333,7 @@ const View = () => { e.preventDefault()}>