diff --git a/moon/.env.local b/moon/.env.local new file mode 100644 index 000000000..6a35dc570 --- /dev/null +++ b/moon/.env.local @@ -0,0 +1 @@ +NEXT_MEGA_API_URL=http://localhost:8000 diff --git a/moon/.gitignore b/moon/.gitignore index 72767b6bf..e02444ac3 100644 --- a/moon/.gitignore +++ b/moon/.gitignore @@ -26,7 +26,7 @@ yarn-debug.log* yarn-error.log* # local env files -.env*.local +# .env*.local # vercel .vercel diff --git a/moon/next.config.js b/moon/next.config.js new file mode 100644 index 000000000..568c27213 --- /dev/null +++ b/moon/next.config.js @@ -0,0 +1,47 @@ +/** @type {import('next').NextConfig} */ + +const nextConfig = { + reactStrictMode: true, + transpilePackages: [ + // antd & deps + // https://github.com/vercel/next.js/issues/65707 + // https://github.com/ant-design/ant-design/issues/46053#issuecomment-1905553667 + "@ant-design", + "@rc-component", + "antd", + "rc-cascader", + "rc-checkbox", + "rc-collapse", + "rc-dialog", + "rc-drawer", + "rc-dropdown", + "rc-field-form", + "rc-image", + "rc-input", + "rc-input-number", + "rc-mentions", + "rc-menu", + "rc-motion", + "rc-notification", + "rc-pagination", + "rc-picker", + "rc-progress", + "rc-rate", + "rc-resize-observer", + "rc-segmented", + "rc-select", + "rc-slider", + "rc-steps", + "rc-switch", + "rc-table", + "rc-tabs", + "rc-textarea", + "rc-tooltip", + "rc-tree", + "rc-tree-select", + "rc-upload", + "rc-util", + ], +} + +module.exports = nextConfig diff --git a/moon/next.config.mjs b/moon/next.config.mjs deleted file mode 100644 index 4678774e6..000000000 --- a/moon/next.config.mjs +++ /dev/null @@ -1,4 +0,0 @@ -/** @type {import('next').NextConfig} */ -const nextConfig = {}; - -export default nextConfig; diff --git a/moon/package.json b/moon/package.json index 76638da89..b4993af12 100644 --- a/moon/package.json +++ b/moon/package.json @@ -21,7 +21,7 @@ "github-markdown-css": "^5.6.1", "highlight.js": "^11.9.0", "lexical": "^0.16.0", - "next": "14.2.4", + "next": "^14.2.5", "prism-react-renderer": "^2.3.1", "react": "^18.3.1", "react-dom": "^18.3.1", diff --git a/moon/src/components/CodeTable.module.css b/moon/src/components/CodeTable.module.css index 4800c03be..da05d4f87 100644 --- a/moon/src/components/CodeTable.module.css +++ b/moon/src/components/CodeTable.module.css @@ -1,86 +1,9 @@ -.projectName { - display: flex; -} - .fileTableIcon { width: 23px; height: 23px; margin-right: 8px; } - -.innerTable { - overflow: hidden; - --tw-shadow: 0 1px 3px 0 rgb(0 0 0 / 0.1), 0 1px 2px -1px rgb(0 0 0 / 0.1); - --tw-shadow-colored: 0 1px 3px 0 var(--tw-shadow-color), 0 1px 2px -1px var(--tw-shadow-color); - box-shadow: var(--tw-ring-offset-shadow, 0 0 #0000), var(--tw-ring-shadow, 0 0 #0000), var(--tw-shadow); - --tw-ring-offset-shadow: var(--tw-ring-inset) 0 0 0 var(--tw-ring-offset-width) var(--tw-ring-offset-color); - --tw-ring-shadow: var(--tw-ring-inset) 0 0 0 calc(1px + var(--tw-ring-offset-width)) var(--tw-ring-color); - border-radius: 0.5rem; -} - -.dirShowTable { - min-width: 100%; - min-width: 100%; - --tw-divide-y-reverse: 0; - border-bottom-width: calc(1px * calc(1 - var(--tw-divide-y-reverse))); - --tw-divide-opacity: 1; - border-color: rgb(209 213 219 / var(--tw-divide-opacity)); - border-collapse: collapse; - -} - -.dirShowTableThead { - background-color: rgb(249 250 251); -} - -.dirShowTableTr { - padding-top: 0.875rem; - padding-bottom: 0.875rem; - padding-left: 1rem; - padding-right: 0.75rem; - text-align: left; - font-size: 0.875rem; - line-height: 1.25rem; - font-weight: 600; - --tw-text-opacity: 1; - color: rgb(17 24 39 / var(--tw-text-opacity)); -} - -.dirShowTableTbody> :not([hidden])~ :not([hidden]) { - --tw-divide-y-reverse: 0; - border-top-width: calc(1px * calc(1 - var(--tw-divide-y-reverse))); - border-bottom-width: calc(1px * var(--tw-divide-y-reverse)); - border-color: rgb(229 231 235); - background-color: rgb(255 255 255); -} - -.projectName { - white-space: nowrap; - padding-top: 1rem; - padding-bottom: 1rem; - padding-right: 0.75rem; - font-size: 0.875rem; - line-height: 1.25rem; - font-weight: 500; - --tw-text-opacity: 1; - color: rgb(17 24 39 / var(--tw-text-opacity)); - padding-left: 1rem; -} - -.projectCommitMsg { - white-space: nowrap; - padding-left: 1rem; - padding-right: 0.75rem; - padding-top: 1rem; - padding-bottom: 1rem; - font-size: 0.875rem; - line-height: 1.25rem; - - --tw-text-opacity: 1; - color: rgb(107 114 128 / var(--tw-text-opacity)); -} - .readmeContainer { margin-top: 2rem; margin-left: 1rem; @@ -99,11 +22,3 @@ --tw-ring-shadow: var(--tw-ring-inset) 0 0 0 calc(1px + var(--tw-ring-offset-width)) var(--tw-ring-color); } - - - -/* - -.token-line .comment { - white-space: pre-wrap; -} */ \ No newline at end of file diff --git a/moon/src/components/CodeTable.tsx b/moon/src/components/CodeTable.tsx index 661d1d66c..c4bd7edd7 100644 --- a/moon/src/components/CodeTable.tsx +++ b/moon/src/components/CodeTable.tsx @@ -7,13 +7,69 @@ import folderPic from '../../public/icons/folder.svg' import filePic from '../../public/icons/file.svg' import Image from 'next/image' import styles from './CodeTable.module.css' +import { Space, Table, TableProps } from 'antd/lib' + +export interface DataType { + oid: string; + name: string; + content_type: string; + message: string; + date: number; +} const CodeTable = ({ directory, readmeContent, showTree }) => { const router = useRouter(); - const currentProjectDir = directory || []; const fileCodeContainerStyle = showTree ? { width: '80%', marginLeft: '17%', borderRadius: '0.5rem', marginTop: '10px' } : { width: '90%', margin: '0 auto', borderRadius: '0.5rem', marginTop: '10px' }; - const dirShowTrStyle = { borderBottom: '1px solid rgba(0, 0, 0, 0.1)', } + + var columns: TableProps['columns'] = [ + { + title: 'Name', + dataIndex: ['name', 'content_type'], + key: 'name', + render: (_, record) => { + return <> + {record.content_type === "file" && + + File icon + handleFileClick(record)}>{record.name} + + } + {record.content_type === "directory" && + + File icon + handleDirectoryClick(record)}>{record.name} + } + + } + }, + { + title: 'Message', + dataIndex: 'message', + key: 'message', + render: (text) => {text}, + }, + { + title: 'Date', + dataIndex: 'date', + key: 'date', + render: (_, { date }) => ( + <> + {date && formatDistance(fromUnixTime(date), new Date(), { addSuffix: true })} + + ) + }, + { + title: 'Action', + key: 'action', + render: (_, record) => ( + + Publish {record.name} + Revoke + + ), + }, + ]; const handleFileClick = (file) => { const { path } = router.query; @@ -44,12 +100,11 @@ const CodeTable = ({ directory, readmeContent, showTree }) => { router.push('/') } else { router.push(`/tree/${safePath.slice(0, -1).join('/')}`); - } }; // sort by file type, render folder type first - const sortedProjects = currentProjectDir.sort((a, b) => { + const sortedDir = directory.sort((a, b) => { if (a.content_type === 'directory' && b.content_type === 'file') { return -1; } else if (a.content_type === 'file' && b.content_type === 'directory') { @@ -60,57 +115,8 @@ const CodeTable = ({ directory, readmeContent, showTree }) => { }); return ( -
-
- - - - - - - - - - {showTree && ( - - - - - - )} - - {sortedProjects.map((project) => ( - - {project.content_type === 'file' && ( - - )} - {project.content_type === 'directory' && ( - - )} - - - - ))} - -
- Name - - Message - - Date -
- File icon - handleGoBack()}>.. -
- File icon - handleFileClick(project)}>{project.name} - - File icon - handleDirectoryClick(project)}>{project.name} - {project.message} - {project.date && formatDistance(fromUnixTime(project.date), new Date(), { addSuffix: true })} -
-
+
+ {readmeContent && (
diff --git a/moon/src/pages/index.js.back b/moon/src/pages/index.js.back deleted file mode 100644 index a417b9688..000000000 --- a/moon/src/pages/index.js.back +++ /dev/null @@ -1,417 +0,0 @@ -import Editor from '@/components/editor/Editor'; -import { DownOutlined } from '@ant-design/icons/lib'; -import { Breadcrumb, Tree } from 'antd/lib'; -import axios from 'axios'; -import 'github-markdown-css/github-markdown-light.css'; -import { useRouter } from 'next/router'; -import { Highlight, themes } from "prism-react-renderer"; -import { useEffect, useState } from 'react'; -import ReactDOM from 'react-dom'; -import Markdown from 'react-markdown'; -import { formatDistance, fromUnixTime } from 'date-fns' - -const HomePage = ({ rootDirectory, directory, readmeContent, fileContent, TreeData }) => { - - const router = useRouter(); - const currentProjectDir = directory.items || []; - const [showEditor, setShowEditor] = useState(false); - const [showTree, setShowTree] = useState(false); - const [treeData, setTreeData] = useState(""); - const [updateTree, setUpdateTree] = useState(false); - const [currentPath, setCurrentPath] = useState([]); // for breadcrumb - const { DirectoryTree } = Tree; - const [expandedKeys, setExpandedKeys] = useState([]); - const fileCodeContainerStyle = showTree ? { width: '80%', marginLeft: '17%', borderRadius: '0.5rem', marginTop: '10px' } : { width: '90%', margin: '0 auto', borderRadius: '0.5rem', marginTop: '10px' }; - const dirShowTrStyle = { borderBottom: '1px solid rgba(0, 0, 0, 0.1)', } - - useEffect(() => { - setTreeData(convertToTreeData(rootDirectory.items)); - }, []); - - useEffect(() => { - if (updateTree) { - setUpdateTree(false); - } - }, [updateTree]); - - const handleLineNumberClick = (lineIndex) => { - setShowEditor(!showEditor); - const lineNumberButton = document.getElementsByClassName('codeLineNumber')[lineIndex]; - const codeLineNumber = lineNumberButton.closest('.token-line'); - if (showEditor) { - const editorContainer = document.createElement('div'); - editorContainer.className = 'editor-container'; - - // render the Editor into the container - ReactDOM.render(, editorContainer); - codeLineNumber.parentNode.insertBefore(editorContainer, codeLineNumber.nextSibling); - } else { - const editorContainer = document.querySelector('.editor-container'); - if (editorContainer) { - editorContainer.parentNode.removeChild(editorContainer); - } - } - - }; - - const handleFileClick = (file) => { - setShowTree(true); - router.push({ - query: { ...router.query, name: `${file.name}` } - }); - }; - - const handleDirectoryClick = async (directory) => { - const c_path = router.query.path || ''; - const newPath = `${c_path}/${directory.name}`; - - // router.push(`/?path=${directory.path}`); - router.push({ - pathname: router.pathname, - query: { ...router.query, path: newPath }, - }); - - setShowTree(true); - - try { - const response = await fetch(`/api/tree?path=${encodeURIComponent(directory.path)}`); - - if (!response.ok) { - throw new Error('Failed to fetch tree data'); - } - - const responseData = await response.json(); - console.log('Response data:', responseData); - - const subTreeData = convertToTreeData(responseData.items); - const newTreeData = appendTreeData(treeData, subTreeData, directory.id); - setTreeData(newTreeData); - setUpdateTree(true); - setExpandedKeys([...expandedKeys, directory.id]); - setCurrentPath([...currentPath, directory.name]); // for breadcrumb - console.log(newTreeData); - console.log(treeData); - } catch (error) { - console.error('Error fetching tree data:', error); - } - }; - - const handleGoBack = () => { - router.back(); - }; - - // sort by file type, render folder type first - const sortedProjects = currentProjectDir.sort((a, b) => { - if (a.content_type === 'directory' && b.content_type === 'file') { - return -1; - } else if (a.content_type === 'file' && b.content_type === 'directory') { - return 1; - } else { - return 0; - } - }); - - - // sortProjectsByType function to sort projects by file type - const sortProjectsByType = (projects) => { - return projects.sort((a, b) => { - if (a.content_type === 'directory' && b.content_type === 'file') { - return -1; // directory comes before file - } else if (a.content_type === 'file' && b.content_type === 'directory') { - return 1; // file comes after directory - } else { - return 0; // maintain original order - } - }); - }; - - - - const onSelect = (keys, info) => { - router.push(`/?object_id=${keys}`); - console.log('Trigger Select', keys, info); - }; - - - // convert the dir to tree data - const convertToTreeData = (responseData) => { - // console.log("!!!!!!!!!!!!in convert"); - return sortProjectsByType(responseData).map(item => { - const treeItem = { - title: item.name, - key: item.id, - isLeaf: item.content_type !== 'directory', - path: item.path, - expanded: false, // initialize expanded state to false - children: [] // eneure every node having the children element - }; - return treeItem; - }); - }; - - // append the clicked dir to the treeData - const appendTreeData = (treeData, subItems, clickedNodeKey) => { - return treeData.map(item => { - if (item.key === clickedNodeKey) { - return { - ...item, - children: subItems - }; - } else if (Array.isArray(item.children)) { - return { - ...item, - children: appendTreeData(item.children, subItems, clickedNodeKey) - }; - } - }); - }; - - const onExpand = async (keys, { expanded, node }) => { - // push new url and query to router - console.log("OnExpanded!"); - console.log("keys", keys); - console.log("node", node.path); - // router.push({ query: { repo_path: "/projects/freighter", object_id: node.key } }); - var responseData = ''; - try { - const response = await fetch(`/api/tree?path=${encodeURIComponent(node.path)}`); - - if (!response.ok) { - throw new Error('Failed to fetch tree data'); - } - - console.log('Response status:', response.status); - - responseData = await response.json(); - console.log('Response data:', responseData); - - } catch (error) { - console.error('Error fetching tree data:', error); - } - // onRenderTree(node.key); - if (expanded) { - const subTreeData = convertToTreeData(responseData.items); - const newTreeData = appendTreeData(treeData, subTreeData, node.key); - setExpandedKeys([...expandedKeys, node.key]); - setTreeData(newTreeData); - setCurrentPath([...currentPath, node.title]); // for breadcrumb - } else { - setExpandedKeys(expandedKeys.filter(key => key !== node.key)); - } - }; - - - const handleBreadcrumbClick = async (index, key) => { - if (index === 0) { - console.log("clicked root path"); - setShowTree(false); - router.push(`/?path=/`); - } else { - setCurrentPath(currentPath.slice(0, index + 1)); - router.push(`/?path=${key}`); - - // reRender the tree for back to clicked dir - var responseData = ''; - try { - const response = await fetch(`/api/tree?path=${encodeURIComponent(key)}`); - - if (!response.ok) { - throw new Error('Failed to fetch tree data'); - } - - console.log('Response status:', response.status); - - responseData = await response.json(); - console.log('Response data:', responseData); - - } catch (error) { - console.error('Error fetching tree data:', error); - } - - const subTreeData = convertToTreeData(responseData.items); - const newTreeData = appendTreeData(treeData, subTreeData, key); - setExpandedKeys([...expandedKeys, key]); - setTreeData(newTreeData); - } - - }; - - const breadCrumbItems = currentPath.map((path, index) => ({ - title: path, - onClick: () => handleBreadcrumbClick(index, expandedKeys[index - 1]), - })); - - - return ( -
- {showTree && ( -
- } - expandedKeys={expandedKeys} - /> -
- )} - {showTree && ( - - )} - - {!fileContent && ( -
-
-
- - - - - - - - - {showTree && ( - - - - - - )} - - {sortedProjects.map((project) => ( - - {project.content_type === 'file' && ( - - )} - {project.content_type === 'directory' && ( - - )} - - - - ))} - -
- Name - - Message - - Date -
- File icon - handleGoBack()}>.. -
- File icon - handleFileClick(project)}>{project.name} - - File icon - handleDirectoryClick(project)}>{project.name} - {project.message} - {formatDistance(fromUnixTime(project.date), new Date(), { addSuffix: true })} -
-
- {readmeContent && ( -
-
- {readmeContent} -
-
- )} -
- )} - - {fileContent && ( -
-
- - -
- - - {({ className, style, tokens, getLineProps, getTokenProps }) => ( -
-                                {tokens.map((line, i) => (
-                                    
- - {i + 1} - {line.map((token, key) => ( - - ))} -
- ))} -
- )} -
-
- )} - - - ); -}; - -export async function getServerSideProps(context) { - const MEGA_URL = 'http://localhost:8000'; - // get the parameters form context - const { path, name } = context.query; - const rootDirectory = (await axios.get(`${MEGA_URL}/api/v1/tree?path=/`)).data; - - // obtain the current directory - const response = path - ? await axios.get(`${MEGA_URL}/api/v1/tree-commit-info?path=${encodeURIComponent(path)}`) - : await axios.get(`${MEGA_URL}/api/v1/tree-commit-info?path=/`); - - const directory = response.data.data; - var readmeContent = ''; - var fileContent = ''; - var TreeData = ''; - - // get the file content - if (name) { - try { - const fileResponse = await axios.get(`${MEGA_URL}/api/v1/blob?path=${path}&name=${name}`, { withCredentials: true }); - fileContent = fileResponse.data.plain_text; - } catch (error) { - console.error("Error fetching file content:", error); - } - } - - // get the readme file content - for (const project of directory.items || []) { - if (project.name === 'README.md' && project.content_type === 'file') { - try { - const response = await axios.get(`${MEGA_URL}/api/v1/blob?path=${path}&name=${project.name}`, { withCredentials: true }); - readmeContent = response.data.plain_text; - break; - } catch (error) { - console.error("Error fetching README content:", error); - } - - } - } - - return { - props: { - rootDirectory, - directory, - readmeContent, - fileContent, - TreeData, - }, - }; -} - - -export default HomePage; \ No newline at end of file diff --git a/moon/src/styles/Bottombar.css b/moon/src/styles/Bottombar.css deleted file mode 100644 index 0fe78a59a..000000000 --- a/moon/src/styles/Bottombar.css +++ /dev/null @@ -1,30 +0,0 @@ -.BottombarContainer { - margin-top: 20px; - margin-bottom: 10px; -} - -.BottombarUl { - display: flex; - justify-content: center; - align-items: center; - width: 100%; -} - -.BottombarContainer .BottombarItems:first-child { - display: flex; - align-items: center; -} - -.BottombarContainer .BottombarItems:not(:first-child):hover { - color: blue; -} - -.BottombarItems { - margin-right: 1.5%; - color: rgb(108, 108, 108); -} - -.BottombarItemsLog { - width: 40px; - margin-right: 5px; -} \ No newline at end of file diff --git a/moon/src/styles/TopNavbar.css b/moon/src/styles/TopNavbar.css deleted file mode 100644 index fbf041ace..000000000 --- a/moon/src/styles/TopNavbar.css +++ /dev/null @@ -1,102 +0,0 @@ -.navContainer { - background-color: rgba(211, 222, 234, 0.295); - box-shadow: 0px 4px 8px rgba(0, 0, 0, 0.1); -} - -.logo-container { - display: flex; - align-items: center; - justify-content: space-between; -} - - -.navRight { - margin-right: 5px; -} - -.logOfMega { - height: 20%; - width: 20%; - margin-left: 5px; -} - -.titleOfMega { - font-size: 25px; - font-weight: 500; - margin-left: 5%; -} - -.navSerchInput { - width: 300px; - height: 40px; - padding-left: 10px; -} - -.navSearchNextContainer { - display: block; -} - -.navSearchContainer input:not(:placeholder-shown)+.navSearchNextContainer { - display: none; -} - -.navLogs { - height: 40px; - width: 40px; -} - -.navRightItem { - margin-left: 10px; - -} - -.navRight, -.navLeft { - display: flex; - align-items: center; -} - -.logOfHead { - height: 60px; - width: 60px; -} - -.navLinkIcons { - display: flex; - justify-content: center; -} - -.navLinkUl { - display: flex; - align-items: center; - margin-top: 0; -} - -.navLinkUl .navLinkLi:not(:first-child) { - margin-left: 30px; -} - -.navLinkLi { - display: flex; - font-weight: 500; - color: rgba(0, 0, 0, 0.608); - font-size: 20px; - align-items: center; - border-bottom: 3px solid transparent; - list-style: none; - -} - -.navLinkLi:hover { - border-bottom: 3px solid rgba(21, 21, 176, 0.559); -} - -.navPagesIcon { - margin-right: 5px; - width: 35px; -} - -a { - color: rgba(0, 0, 0, 0.608); - text-decoration: none; -} \ No newline at end of file