diff --git a/.dumi/components/AboutUs.tsx b/.dumi/components/AboutUs.tsx deleted file mode 100644 index 55c855d..0000000 --- a/.dumi/components/AboutUs.tsx +++ /dev/null @@ -1,119 +0,0 @@ -import { useIntl } from '../hooks/useIntl'; -import { WechatOutlined } from '@ant-design/icons'; -import { Typography, message } from 'antd'; -import copy from 'copy-to-clipboard'; -import React, { useEffect, useRef } from 'react'; -import styled from 'styled-components'; - -const ImgContainer = styled.div` - position: fixed; - right: 20px; - bottom: 20px; - border-radius: 8px; - transition: all 0.3s ease; - overflow: hidden; - z-index: 9; - background-color: #fff; - overflow: hidden; - white-space: nowrap; - background-color: var(--background-color); - box-shadow: - 0 3px 6px -4px rgba(0, 0, 0, 0.12), - 0 6px 16px 0 rgba(0, 0, 0, 0.08), - 0 9px 28px 8px rgba(0, 0, 0, 0.05); -`; - -const Content = styled.div` - padding: 10px; - - img { - width: 100%; - height: 100%; - object-fit: contain; - } -`; - -const Icon = styled(WechatOutlined)` - width: 40px; - height: 40px; - position: fixed; - right: 20px; - bottom: 20px; - cursor: pointer; - color: #7bb32e; - font-size: 40px; - z-index: 10; -`; - -const { Text } = Typography; - -const AboutUs = () => { - const [showQRCode, setShowQRCode] = React.useState(window.innerWidth >= 1280); - const { - Messages: { PARAGRAPH }, - } = useIntl(); - const QRCodeRef = useRef(null); - - useEffect(() => { - const attributes = showQRCode - ? { width: '220px', padding: '10px', opacity: 1 } - : { width: '100px', padding: 0, opacity: 0 }; - if (QRCodeRef.current) { - Object.assign(QRCodeRef.current?.style || {}, attributes); - } - }, [showQRCode]); - - useEffect(() => { - const handleClick = (e: MouseEvent) => { - if ( - QRCodeRef.current && - !QRCodeRef.current.contains(e.target as HTMLElement) - ) { - setShowQRCode(false); - } - }; - document.addEventListener('click', handleClick); - return () => { - document.removeEventListener('click', handleClick); - }; - }, []); - - return ( - <> - -
- {PARAGRAPH.ContactUs} -
- { - copy('feidongni.fdn@antgroup.com', { - onCopy: () => { - message.success(PARAGRAPH.CopiedToClipboard); - }, - }); - }} - > - feidongni.fdn@antgroup.com - -
- {PARAGRAPH.FollowUs} -
- {PARAGRAPH.SPGFramework} -
- - - -
- {!showQRCode && ( - { - e.stopPropagation(); - setShowQRCode(true); - }} - /> - )} - - ); -}; - -export default AboutUs; diff --git a/.dumi/components/Announcement/HoverCard.tsx b/.dumi/components/Announcement/HoverCard.tsx new file mode 100644 index 0000000..5c61825 --- /dev/null +++ b/.dumi/components/Announcement/HoverCard.tsx @@ -0,0 +1,77 @@ +import React, { useEffect, useRef } from 'react'; +import { Card } from 'antd'; +import type { CardProps } from 'antd'; +import styled from 'styled-components'; + +const CardContainer = styled(Card)` + position: relative; + z-index: 1; + min-width: 300px; + min-height: 50px; + color: #fff; + background-color: transparent; + overflow: hidden; // 超出特效的区域隐藏掉 + cursor: pointer; + + &:hover:after { + width: 250px; + height: 250px; + left: var(--x); + top: var(--y); + } + + /* 鼠标hover光晕渐变 */ + &:after { + position: absolute; + left: 50%; + top: 50%; + z-index: 6; + transform: rotateX(-0.03deg) rotateY(-0.03deg) translate(-50%, -50%); + transition: + width 0.2s ease, + height 0.2 ease; + width: 0; + height: 0; + opacity: 0.7; + content: ''; + background: radial-gradient(circle closest-side, #133b71, transparent); + } +`; + +const Content = styled.div` + position: relative; + z-index: 5; + width: 100%; + height: 100%; +`; + +const HoverCard = React.memo((props) => { + const ref = useRef(null); + const { children, ...restProps } = props; + + useEffect(() => { + const containerRef = ref.current; + const handleMouseMove = (event: MouseEvent) => { + const targetRect = (event?.target as Element)?.getBoundingClientRect(); + if (!targetRect || !containerRef) return; + const xPosition = event.clientX - targetRect.left; + const yPosition = event.clientY - targetRect.top; + containerRef.style.setProperty('--x', xPosition + 'px'); + containerRef.style.setProperty('--y', yPosition + 'px'); + }; + containerRef?.addEventListener('mousemove', handleMouseMove); + return () => { + containerRef?.removeEventListener('mousemove', handleMouseMove); + }; + }, []); + + return ( +
+ + {children} + +
+ ); +}); + +export default HoverCard; diff --git a/.dumi/components/Announcement/index.tsx b/.dumi/components/Announcement/index.tsx new file mode 100644 index 0000000..6002f97 --- /dev/null +++ b/.dumi/components/Announcement/index.tsx @@ -0,0 +1,93 @@ +import React from 'react'; +import styled from 'styled-components'; +import { useIntl } from '../../hooks/useIntl'; +import HoverCard from './HoverCard'; +import { Flex, Typography } from 'antd'; + +const { Text } = Typography; + +const FlexContainer = styled(Flex)` + display: flex; + flex-wrap: wrap; + max-width: min(1200px, 90%); + gap: 24px; + margin: 0 auto; + + @media (max-width: 900px), (max-width: 480px) { + gap: 16px; + flex-direction: column; + } +`; + +const HoverCardContainer = styled(HoverCard)` + height: 100%; + border: none; + background-image: linear-gradient( + 106deg, + rgba(255, 255, 255, 0.12) 0%, + rgba(255, 255, 255, 0.1) 100% + ); + border-radius: 16px; + + .openagl-card-body { + height: 100%; + + @media (max-width: 900px) { + padding: 16px; + } + + @media (max-width: 480px) { + padding: 12px; + } + } +`; + +const Title = styled(Flex)` + overflow: hidden; + align-items: center; + justify-content: center; + gap: 8px; + opacity: 0.95; + font-weight: 500; +`; + +const Description = styled(Text)` + display: inline-block; + width: 100%; + font-size: 14px; + font-weight: 400; + opacity: 0.45; + margin-top: 9px; + text-align: center; +`; + +const Announcement = React.memo(() => { + const { + Messages: { ANNOUNCEMENT }, + } = useIntl(); + + const handleOpenLink = (linkUrl?: string) => { + if (!linkUrl) return; + window.open(linkUrl, '_blank', 'noopener=yes,noreferrer=yes'); + }; + + if (ANNOUNCEMENT.length === 0) { + return
; + } + + return ( + + {ANNOUNCEMENT.map(({ cover, title, description, link }) => ( + handleOpenLink(link)}> + + <img src={cover} /> + <span>{title}</span> + + {description} + + ))} + + ); +}); + +export default Announcement; diff --git a/.dumi/components/SpgCaseItem.tsx b/.dumi/components/BusinessApplicationItem.tsx similarity index 82% rename from .dumi/components/SpgCaseItem.tsx rename to .dumi/components/BusinessApplicationItem.tsx index 9775b57..a0d4c35 100644 --- a/.dumi/components/SpgCaseItem.tsx +++ b/.dumi/components/BusinessApplicationItem.tsx @@ -3,16 +3,14 @@ import { Space, Typography } from 'antd'; const { Title, Text } = Typography; -const Container = styled.div` - margin-bottom: 45px; -`; +const Container = styled.div``; const ContentContainer = styled.div` display: grid; grid-template: repeat(1, 1fr) / repeat(2, 1fr); gap: 15px; - @media (max-width: 814px) { + @media (max-width: 900px) { grid-template: repeat(1, 1fr) / repeat(1, 1fr); } `; @@ -22,15 +20,9 @@ const Content = styled.div` flex-direction: column; justify-content: space-around; gap: 15px; - - @media (max-width: 1280px) { - } - @media (max-width: 768px) { - } `; const ItemBackground = styled.div` - background-color: var(--background-color-pure); border-radius: 15px; `; @@ -83,7 +75,7 @@ const ImgContainer = styled.div` } `; -export type CaseItemProps = { +export type BusinessApplicationItemProps = { title: string; desc: string; details: { @@ -94,12 +86,11 @@ export type CaseItemProps = { reverse?: boolean; }; -const SpgCaseItem = (props: CaseItemProps) => { - const { title, desc, details, imgUrl, reverse } = props; +const BusinessApplicationItem = (props: BusinessApplicationItemProps) => { + const { desc, details, imgUrl, reverse } = props; return ( - {title} - + {desc} @@ -121,7 +112,7 @@ const SpgCaseItem = (props: CaseItemProps) => { ); })} - + @@ -130,4 +121,4 @@ const SpgCaseItem = (props: CaseItemProps) => { ); }; -export default SpgCaseItem; +export default BusinessApplicationItem; diff --git a/.dumi/components/ButtonGroup/index.tsx b/.dumi/components/ButtonGroup/index.tsx new file mode 100644 index 0000000..4c6d6ba --- /dev/null +++ b/.dumi/components/ButtonGroup/index.tsx @@ -0,0 +1,88 @@ +import { + FileTextOutlined, + GithubOutlined, + CloudDownloadOutlined, +} from '@ant-design/icons'; +import { Button } from 'antd'; +import React from 'react'; +import styled from 'styled-components'; +import { useIntl } from '../../hooks/useIntl'; +import { usePush } from '../../hooks/usePush'; + +const Container = styled.div` + max-width: min(1200px, 90%); + display: flex; + flex-wrap: wrap; + justify-content: center; + align-items: center; + gap: 20px; + margin: 40px auto; + + @media (max-width: 768px) { + margin: 30px auto; + gap: 15px; + } + + @media (max-width: 480px) { + flex-direction: column; + margin: 20px auto; + gap: 10px; + } +`; + +const CommonButton = styled(Button)` + display: flex; + align-items: center; + justify-content: center; + width: 140px; + height: 46px; + color: var(--text-color); + font-size: 1rem; + + @media (max-width: 480px) { + width: 100%; + height: 40px; + } +`; + +const PanelButton = React.memo(() => { + const { + intl, + Messages: { + BUTTON_GROUP: { Github, Documentation, WhitePaper }, + }, + } = useIntl(); + const push = usePush(); + + return ( + + {Github && ( + } + type="primary" + onClick={() => window.open(Github)} + > + GitHub + + )} + {Documentation && ( + } + onClick={() => push(Documentation)} + > + {intl('帮助文档', 'Document')} + + )} + {WhitePaper && ( + } + onClick={() => push(WhitePaper)} + > + {intl('白皮书', 'WhitePaper')} + + )} + + ); +}); + +export default PanelButton; diff --git a/.dumi/components/Contact.tsx b/.dumi/components/Contact.tsx new file mode 100644 index 0000000..b3b7768 --- /dev/null +++ b/.dumi/components/Contact.tsx @@ -0,0 +1,82 @@ +import { GithubOutlined } from '@ant-design/icons'; +import { Typography } from 'antd'; +import styled from 'styled-components'; +import { useIntl } from '../hooks/useIntl'; +import QRCodeComponent from './QRCode'; + +const { Title, Link } = Typography; + +const ItemTitle = styled(Title).attrs({ + level: 5, +})` + margin-top: 0; +`; + +const ItemLink = styled(Link).attrs({ + type: 'secondary', + target: '_blank', +})``; + +const ContactContainer = styled.div` + position: relative; + max-width: min(1200px, 90%); + display: flex; + flex-wrap: wrap; + align-items: center; + justify-content: space-around; + gap: 10px; + margin: 0 auto; + padding: 30px 0; + + @media (max-width: 480px) { + gap: 20px; + flex-direction: column; + align-items: start; + } +`; + +const GitHubContent = styled.div``; + +const CommunityContent = styled.div``; + +const EmailContent = styled.div``; + +const Contact = () => { + const { + Messages: { + CONTACT: { Github, Community, Email, QRCode }, + }, + } = useIntl(); + + return ( + + {Github.url && ( + + {Github.title} + + {Github.name} + + + )} + {Community.url && ( + + {Community.title} + {Community.name} + + )} + {Email.email && ( + + {Email.title} +
+ + {Email.name}: {Email.email} + +
+
+ )} + {QRCode.url && } +
+ ); +}; + +export default Contact; diff --git a/.dumi/components/CustomItem.tsx b/.dumi/components/CustomItem.tsx index 68c73ad..2996cb1 100644 --- a/.dumi/components/CustomItem.tsx +++ b/.dumi/components/CustomItem.tsx @@ -10,9 +10,7 @@ type Props = { }; const Card = styled.div` - border: 1px solid var(--border-color); border-radius: 8px; - background-color: var(--background-color); `; const Cover = styled.div` @@ -21,7 +19,7 @@ const Cover = styled.div` padding: 20px; justify-content: center; align-items: center; - border-radius: 8px 8px 0 0; + border-radius: 8px; background-color: var(--image-background-color); `; @@ -33,9 +31,7 @@ const Img = styled.img` `; const Content = styled.div` - padding: 24px; text-align: center; - background-color: var(--background-color); `; const CustomItem = (props: Props) => { @@ -46,7 +42,7 @@ const CustomItem = (props: Props) => { - {title} + {title} {detail} diff --git a/.dumi/components/GitHub.tsx b/.dumi/components/GitHub.tsx new file mode 100644 index 0000000..93f0633 --- /dev/null +++ b/.dumi/components/GitHub.tsx @@ -0,0 +1,79 @@ +import React from 'react'; +import styled from 'styled-components'; +import { GithubOutlined, ForkOutlined, StarOutlined } from '@ant-design/icons'; +import { Flex } from 'antd'; +import { useGithubRepoStats } from '../hooks/useGitHubRepoStats'; +import { useIntl } from '../hooks/useIntl'; + +const Container = styled(Flex).attrs({ justify: 'end' })` + position: relative; + width: min(1200px, 90%); + padding: 10px 0; + margin: 0 auto; +`; + +const Content = styled.div` + display: grid; + grid-template-columns: repeat(3, 1fr); + align-items: center; + justify-items: center; + width: 196px; + height: 55px; + gap: 5px; + padding: 5px; + border-radius: 8px; + background-image: linear-gradient( + 105deg, + rgba(255, 255, 255, 0.06) 0%, + rgba(255, 255, 255, 0.04) 100% + ); + + @media (max-width: 900px), (max-width: 480px) { + width: 150px; + height: 45px; + } +`; + +const Item = styled(Flex)``; + +const Text = styled.span` + margin-left: 4px; + color: var(--text-color); +`; + +const GitHub = React.memo(() => { + const { + Messages: { REPO }, + } = useIntl(); + + const url = REPO; + const parts = url.split('/'); + const groupName = parts[3]; + const repoName = parts[4]; + const { stars, forks } = useGithubRepoStats(groupName, repoName); + + const handleOpenLink = () => { + if (!url) return; + window.open(url, '_blank', 'noopener=yes,noreferrer=yes'); + }; + + return ( + + + + + + + + {forks ?? 0} + + + + {stars ?? 0} + + + + ); +}); + +export default GitHub; diff --git a/.dumi/components/QRCode.tsx b/.dumi/components/QRCode.tsx new file mode 100644 index 0000000..d59d9c3 --- /dev/null +++ b/.dumi/components/QRCode.tsx @@ -0,0 +1,68 @@ +import React from 'react'; +import styled from 'styled-components'; + +const Flex = styled.div` + display: flex; + align-items: center; + justify-content: center; +`; + +const Container = styled(Flex)` + flex-direction: column; + row-gap: 12px; + width: 180px; + height: 180px; + background-image: linear-gradient(142deg, #20262e 2%, #0f141c 99%); + box-shadow: + 0 2px 2px 0 #3e495f, + inset 0 2px 3px 0 rgba(0, 0, 0, 0.4); + border-radius: 8px; + + @media (max-width: 900px), (max-width: 480px) { + width: 140px; + height: 140px; + } + + @media (max-width: 600px) { + align-self: center; + } +`; + +const ImgContainer = styled(Flex)` + width: 120px; + height: 120px; + font-size: 16px; + border-radius: 8px; + padding: 10px; + background-color: var(--text-color); + + @media (max-width: 900px), (max-width: 480px) { + width: 80px; + height: 80px; + row-gap: 2px; + padding: 8px; + } +`; + +const Text = styled(Flex)` + color: var(--text-color); + font-weight: 400; + font-size: 12px; + opacity: 0.45; + text-align: center; +`; + +interface QRCodeProps { + url: string; + title: string; +} +const QRCode = React.memo(({ url, title }) => ( + + + {title} + + {title} + +)); + +export default QRCode; diff --git a/.dumi/constants/prefix.ts b/.dumi/constants/prefix.ts new file mode 100644 index 0000000..f4a1b47 --- /dev/null +++ b/.dumi/constants/prefix.ts @@ -0,0 +1 @@ +export const PREFIX = 'spg'; diff --git a/.dumi/hooks/useGitHubRepoStats.ts b/.dumi/hooks/useGitHubRepoStats.ts new file mode 100644 index 0000000..4e1cb18 --- /dev/null +++ b/.dumi/hooks/useGitHubRepoStats.ts @@ -0,0 +1,25 @@ +import { useEffect, useState } from 'react'; + +export const useGithubRepoStats = (owner: string, repo: string) => { + const [repoStats, setRepoStats] = useState({ stars: 0, forks: 0 }); + + useEffect(() => { + async function fetchRepoStats() { + try { + const response = await fetch( + `https://api.github.com/repos/${owner}/${repo}`, + ); + const repoData = await response.json(); + setRepoStats({ + stars: repoData.stargazers_count, + forks: repoData.forks, + }); + } catch (error) { + console.error('Error fetching repo stats:', error); + } + } + fetchRepoStats(); + }, [owner, repo]); + + return repoStats; +}; diff --git a/.dumi/hooks/useIntl.ts b/.dumi/hooks/useIntl.ts index 20e29c7..f1a8fa8 100644 --- a/.dumi/hooks/useIntl.ts +++ b/.dumi/hooks/useIntl.ts @@ -14,51 +14,67 @@ export const useIntl = () => { const Messages = useMemo(() => { return { - PARAGRAPH: { - whyChooseSPG: intl('为什么选择SPG', 'Why Choose SPG'), - SPGFeaturesSemanticExamples: intl( - 'SPG特性-语义增强示例', - 'SPG Features - Semantic Enhancement Examples', - ), - DeepSemanticNetworking: intl( - '离散实体要素深度语义网络化,稀疏关系自动补全显性稠密', - 'Deep Semantic Networking of Discrete Entity Elements, Automatic Completion of Sparse Relationships for Enhanced Density', - ), - SemanticEnhancedProperties: intl( - '属性图语义增强', - 'Semantic Enhancement of Property Graphs', - ), - SemanticEnhancedPropertiesImg: intl( - 'https://mdn.alipayobjects.com/huamei_xgb3qj/afts/img/A*TdfeRIfHnisAAAAAAAAAAAAADtmcAQ/original', - 'https://mdn.alipayobjects.com/huamei_xgb3qj/afts/img/A*tzHwTJy7TDIAAAAAAAAAAAAADtmcAQ/original', + REPO: 'https://github.com/OpenSPG/openspg', + TITLE: { + abbr: 'SPG', + full: intl( + '语义增强可编程图谱框架', + 'Semantic-Enhanced Programmable Graph', ), - DataToKnowledgeProcess: intl( - '数据到知识生产过程', - 'The Data-to-Knowledge Production Process', + sub: intl( + '新一代企业级知识图谱语义框架', + 'A new generation of enterprise knowledge graph semantic framework', ), - DataToKnowledgeProcessImg: intl( - 'https://mdn.alipayobjects.com/huamei_xgb3qj/afts/img/A*DcYSS7qaYJkAAAAAAAAAAAAADtmcAQ/original', - 'https://mdn.alipayobjects.com/huamei_xgb3qj/afts/img/A*a3i2T4w41AMAAAAAAAAAAAAADtmcAQ/original', - ), - SPGSemanticFramework: intl('SPG语义框架', 'SPG Semantic Framework'), - AccelerateDataIntegration: intl( - '加速企业海量数据知识化集成,无缝衔接AI技术框架应用落地', - 'Accelerating Enterprise-Scale Data Knowledge Integration, Seamless Integration with AI Technology Frameworks for Real-World Applications', - ), - AccelerateDataIntegrationImg: intl( - 'https://mdn.alipayobjects.com/huamei_xgb3qj/afts/img/A*9BKUQYrL56IAAAAAAAAAAAAADtmcAQ/original', - 'https://mdn.alipayobjects.com/huamei_xgb3qj/afts/img/A*eK3wTqkCHnAAAAAAAAAAAAAADtmcAQ/original', - ), - SPGCaseStudies: intl('SPG案例', 'SPG Case Studies'), + }, + BUTTON_GROUP: { + Github: 'https://github.com/OpenSPG/openspg', + Documentation: 'quick-start', + WhitePaper: 'download', + }, + ANNOUNCEMENT: [ + { + title: intl( + '蚂蚁集团 x OpenKG 联合发布', + 'Jointly Released by Ant Group and OpenKG', + ), + description: intl( + '新一代《知识语义框架SPG》白皮书', + 'New Generation of "Knowledge Semantic Framework SPG" Whitepaper', + ), + link: 'https://mp.weixin.qq.com/s?__biz=MzIyOTkzNDczMw==&mid=2247483709&idx=1&sn=8c778f9d35fdbfeb171f2fdd67168299&chksm=e8ba52dfdfcddbc9d6cdb2cd99367c704601399f7b61f47e80094e226a65031856e3bc3a960c&token=2136960064&lang=zh_CN#rd', + cover: + 'https://mdn.alipayobjects.com/huamei_xgb3qj/afts/img/A*i1HwQKSMFo0AAAAAAAAAAAAADtmcAQ/original', + }, + { + title: 'OpenSPG', + description: intl('OpenSPG 开源发布', 'OpenSPG Open Source Release'), + link: 'https://mp.weixin.qq.com/s?__biz=MzIyOTkzNDczMw==&mid=2247483795&idx=1&sn=49e8ed1ee64fa7a2bd010387e11b3fb7&chksm=e8ba5271dfcddb67a3c44fef86de32379b278a821568add62dbaf70dd1470f9c6e59e006f92e&token=2136960064&lang=zh_CN#rd', + cover: + 'https://mdn.alipayobjects.com/huamei_xgb3qj/afts/img/A*uSgFTpFvMcEAAAAAAAAAAAAADtmcAQ/original', + }, + { + title: intl('“新KG”视点', 'Perspective of "New KG"'), + description: intl( + '知识图谱与大语言模型协同模式探究', + 'Exploring the Synergy Between Knowledge Graphs and Large Language Models', + ), + link: 'https://mp.weixin.qq.com/s?__biz=MzIyOTkzNDczMw==&mid=2247483916&idx=1&sn=62e852520ba45b30daff8bddb44a56c7&chksm=e8ba51eedfcdd8f8c90fa6646adc46ba291ea9e4cdab0562a40bbd371e17a43deab36269d1e2&token=2042662316&lang=zh_CN#rd', + cover: + 'https://mdn.alipayobjects.com/huamei_xgb3qj/afts/img/A*9BZfR6NtkjYAAAAAAAAAAAAADtmcAQ/original', + }, + ], + PARAGRAPH: { + TechnicalFeatures: intl('技术特性', 'Technical Features'), + BusinessApplications: intl('业务应用', 'Business Applications'), WhitepaperDownload: intl('白皮书下载', 'Whitepaper Download'), + CooperationPartner: intl('合作伙伴', 'Cooperation Partner'), QuickStart: intl('快速开始', 'Quick Start'), ContactUs: intl('联系我们', 'Contact Us'), CopiedToClipboard: intl('已复制到剪贴板', 'Copied to Clipboard'), FollowUs: intl('关注我们', 'Follow Us'), SPGFramework: intl('语义增强可编程图谱框架', 'SPG Framework'), }, - SPG_FEATURE: {}, - SPG_POINT_CONFIG: [ + TECHNICAL_FEATURES: [ { title: intl( '跨图谱零拷贝融合,连接数据孤岛', @@ -100,7 +116,7 @@ export const useIntl = () => { ), }, ], - SPG_CASE_CONFIG: [ + BUSINESS_APPLICATIONS: [ { title: intl('支付黑产图谱', 'Anti-Black Market'), desc: intl( @@ -248,13 +264,7 @@ export const useIntl = () => { ), }, ], - /**页面底部版权信息配置 */ - COPYRIGHT_INFORMATION_CONFIG: [ - { - title: intl('牵头编写单位', 'Lead Writing Entity'), - unitNames: [intl('蚂蚁科技集团股份有限公司', 'Ant Group Co., Ltd.')], - style: { flex: 0.5 }, - }, + COOPERATION_PARTNER: [ { title: intl('参与编写单位', 'Contributing Entities'), unitNames: [ @@ -280,6 +290,30 @@ export const useIntl = () => { style: { flex: 1 }, }, ], + CONTACT: { + Github: { + title: intl('资源', 'Resources'), + name: 'GitHub', + url: 'https://github.com/OpenSPG/openspg', + }, + Community: { + title: intl('社区', 'Community'), + name: '', + url: '', + }, + Email: { + title: intl('联系我们', 'Contact Us'), + name: intl('邮箱', 'Email'), + email: 'feidongni.fdn@antgroup.com', + }, + QRCode: { + title: intl( + '语义增强可编程图谱框架', + 'Semantic-enhanced Programmable Graph', + ), + url: 'https://mdn.alipayobjects.com/huamei_xgb3qj/afts/img/A*FYxHT5WP0pUAAAAAAAAAAAAADtmcAQ/original', + }, + }, }; }, [intl]); diff --git a/.dumi/hooks/usePush.ts b/.dumi/hooks/usePush.ts new file mode 100644 index 0000000..fbe74ff --- /dev/null +++ b/.dumi/hooks/usePush.ts @@ -0,0 +1,12 @@ +import { history, useLocale } from 'dumi'; + +export const usePush = () => { + const locale = useLocale(); + + return (link: string) => { + // @ts-ignore + const base = locale.base; + if (base === '/') history.push(`/${link}`); + else history.push(`${base}/${link}`); + }; +}; diff --git a/.dumi/hooks/useTheme.ts b/.dumi/hooks/useTheme.ts index 7087359..c41882c 100644 --- a/.dumi/hooks/useTheme.ts +++ b/.dumi/hooks/useTheme.ts @@ -1,6 +1,6 @@ import { useState, useEffect } from 'react'; -const defaultTheme = 'light'; +const defaultTheme = 'dark'; export function useTheme() { const [theme, setTheme] = useState( diff --git a/.dumi/pages/index.tsx b/.dumi/pages/index.tsx index 3ed6ef8..a58d34d 100644 --- a/.dumi/pages/index.tsx +++ b/.dumi/pages/index.tsx @@ -2,42 +2,43 @@ * title: 语义增强可编程知识图谱 */ -import { Button, Descriptions, Tabs } from 'antd'; -import { history, useLocale, usePrefersColor } from 'dumi'; +import { Descriptions, Tabs, Typography } from 'antd'; +import { usePrefersColor } from 'dumi'; import { useEffect } from 'react'; import styled from 'styled-components'; -import AboutUs from '../components/AboutUs'; +import Announcement from '../components/Announcement'; +import BusinessApplicationItem from '../components/BusinessApplicationItem'; +import ButtonGroup from '../components/ButtonGroup'; +import Contact from '../components/Contact'; import CustomItem from '../components/CustomItem'; -import SpgCaseItem from '../components/SpgCaseItem'; +import GitHub from '../components/GitHub'; +import { PREFIX } from '../constants/prefix'; import { useIntl } from '../hooks/useIntl'; +const Container = styled.div` + background: #0f151d; +`; + +const Abbr = styled.span` + color: rgba(67, 155, 255, 1); +`; + +const FullTitle = styled.span``; + +const SubTitle = styled(Typography.Text)` + font-size: 1rem; + opacity: 0.45; + color: var(--text-color); +`; + const Banner = styled.div` - height: 400px; - background-image: url('https://mdn.alipayobjects.com/huamei_xgb3qj/afts/img/A*ZgvDRofu-FsAAAAAAAAAAAAADtmcAQ/original'); - background-size: cover; - background-repeat: no-repeat; - background-position-x: center; - background-position-y: center; + position: relative; user-select: none; display: flex; flex-direction: column; justify-content: center; align-items: center; padding: 0 120px; - @media (max-width: 768px) { - padding: 0px 60px; - } - @media (max-width: 480px) { - padding: 0px 20px; - } -`; - -const Middle = styled.div` - width: 100%; - height: 100%; - display: flex; - flex-direction: column; - justify-content: center; @media (max-width: 768px) { padding: 0 40px; @@ -48,269 +49,164 @@ const Middle = styled.div` } `; -const LeftTitleContainer = styled.div` - max-width: 680px; - margin-bottom: 20px; -`; - const BaseTitle = styled.div` font-size: 32px; font-weight: 600; color: var(--text-color); text-align: center; + margin: 60px 0 20px 0; @media (max-width: 768px) { font-size: 24px; + margin: 40px 0 15px 0; } @media (max-width: 480px) { font-size: 20px; + margin: 20px 0 10px 0; } `; -const Title = styled(BaseTitle)` - text-align: left; - color: var(--color-dark); -`; - -const BtnGroup = styled.div` - display: flex; - gap: 10px; - - @media (max-width: 768px) { - flex-direction: column; - width: 50%; - } - - @media (max-width: 480px) { - width: 60%; - } - - @media (max-width: 360px) { - width: 100%; - } -`; - -const BaseInfo = styled.div` - color: var(--text-color-light); - font-size: 14px; -`; - -const Info = styled(BaseInfo)``; - -const SPG = styled.div` +const TechnicalFeatures = styled.div` + position: relative; width: 100%; - padding: 72px 120px; + max-width: min(1200px, 90%); + margin: auto; text-align: center; - background-color: var(--background-color-pure); - @media (max-width: 768px) { - padding: 50px 40px; - } - @media (max-width: 480px) { - padding: 30px 20px; - } `; -const SPGContent = styled.div` - max-width: 1200px; +const TechnicalFeaturesContent = styled.div` width: 100%; margin: 0 auto; `; -const SPGTitle = styled(BaseTitle)` - margin-bottom: 37px; -`; +const TechnicalFeaturesTitle = styled(BaseTitle)``; -const SPGList = styled.div` +const TechnicalFeaturesList = styled.div` display: grid; grid-gap: 45px; grid-template-columns: repeat(auto-fill, minmax(300px, 1fr)); width: 100%; -`; -const Point = styled.div` - background-color: var(--background-color); - padding: 40px 120px; - text-align: center; @media (max-width: 768px) { - padding: 40px 40px; - } - @media (max-width: 480px) { - padding: 40px 20px; - } -`; - -const PointContent = styled.div` - max-width: 1200px; - margin: 0 auto; - - img { - background-color: var(--image-background-color); - border-radius: 16px; - min-height: 500px; - max-height: 500px; - width: 100%; - height: 100%; - object-fit: contain; - - @media (max-width: 768px) { - min-height: 300px; - } - @media (max-width: 480px) { - min-height: 200px; - } - } -`; - -const PointTitle = styled(BaseTitle)` - margin-bottom: 15px; -`; - -const Framework = styled.div` - text-align: center; - padding: 38px 120px 72px; - background-color: var(--background-color-pure); - - @media (max-width: 768px) { - padding: 38px 40px 72px; + grid-gap: 30px; } @media (max-width: 480px) { - padding: 38px 20px 72px; + grid-gap: 20px; } `; -const FrameworkContent = styled.div` - max-width: 1200px; +const BusinessApplications = styled.div` + position: relative; + max-width: min(1200px, 90%); margin: 0 auto; - img { - border: 1px solid var(--border-color); - border-radius: 16px; - background-color: var(--image-background-color); - width: 100%; - height: 100%; - object-fit: contain; - } `; -const FrameworkTitle = styled(BaseTitle)` - margin-bottom: 15px; -`; - -const FrameworkInfo = styled(BaseInfo)` - margin-bottom: 16px; -`; - -const Case = styled.div<{ theme: string }>` - text-align: center; - padding: 56px 120px 36px; - background-size: cover; - - ${(props) => - props.theme === 'light' && - `background-image: url(https://mdn.alipayobjects.com/huamei_xgb3qj/afts/img/A*-dj1SrmD6XQAAAAAAAAAAAAADtmcAQ/original);`} - - ${(props) => - props.theme === 'dark' && `background-color: var(--background-color);`} - - @media (max-width: 768px) { - padding: 36px 40px 36px; - } +const BusinessApplicationsTitle = styled(BaseTitle)``; - @media (max-width: 480px) { - padding: 20px 20px 36px; +/** 飞碟装饰 */ +const UFODecorate = styled.div` + position: relative; + background-image: linear-gradient( + 113deg, + rgba(255, 255, 255, 0.06) 0%, + rgba(255, 255, 255, 0.04) 100% + ); + border-radius: 16px; + padding: 0 20px 20px 20px; + + &:after { + position: absolute; + top: -20px; + right: -15px; + z-index: 999; + width: 86px; + height: 63px; + content: ''; + background: url('https://mdn.alipayobjects.com/huamei_xgb3qj/afts/img/A*vAHuSbAD7jQAAAAAAAAAAAAADtmcAQ/original') + no-repeat; + background-size: 100%; } `; -const CaseContent = styled.div` - max-width: 1200px; +const CooperationPartner = styled.div<{ theme: string }>` + position: relative; + max-width: min(1200px, 90%); margin: 0 auto; -`; - -const CaseTitle = styled(BaseTitle)` - margin-bottom: 40px; - - @media (max-width: 768px) { - margin-bottom: 30px; - } - - @media (max-width: 480px) { - margin-bottom: 20px; - } -`; - -const Footer = styled.div` - height: 120px; - display: flex; - justify-content: center; - align-items: center; - background-color: var(--background-color); - background-image: url('https://mdn.alipayobjects.com/huamei_xgb3qj/afts/img/A*Rs5FTKaUgTIAAAAAAAAAAAAADtmcAQ/original'); - background-repeat: no-repeat; - user-select: none; -`; - -const Bottom = styled.div<{ theme: string }>` - padding: 40px 120px; - background-color: var(--background-color-invert); background-repeat: no-repeat; user-select: none; ${(props) => props.theme === 'light' && `background-image: url('https://mdn.alipayobjects.com/huamei_xgb3qj/afts/img/A*pv4jRp2PihQAAAAAAAAAAAAADtmcAQ/original');`} - - @media (max-width: 768px) { - padding: 40px 40px; - } - - @media (max-width: 480px) { - padding: 40px 20px; - } `; -const BottomContent = styled.div` +const CooperationPartnerTitle = styled(BaseTitle)``; + +const CooperationPartnerContent = styled.div` display: flex; @media (max-width: 768px) { flex-direction: column; } - .spg-descriptions-title { + .${PREFIX}-descriptions-title { color: var(--text-color-invert); font-size: 14px; } - .spg-descriptions-item-content { + .${PREFIX}-descriptions-item-content { color: var(--text-color-invert-light); } `; +const TopBackground = styled.div` + background: url('https://mdn.alipayobjects.com/huamei_xgb3qj/afts/img/A*O-WRT6y0kVQAAAAAAAAAAAAADtmcAQ/original') + no-repeat; + background-size: cover; + background-position: bottom; + height: 100%; + width: 100%; + position: absolute; + top: 0; + left: 0; +`; + +const MiddleBackground = styled.div` + background: url('https://mdn.alipayobjects.com/huamei_xgb3qj/afts/img/A*5vvRRZY-PoQAAAAAAAAAAAAADtmcAQ/original') + no-repeat; + background-size: cover; + background-position: top; + height: 50%; + width: 100%; + position: absolute; + top: 100%; + left: 0; + opacity: 0.2; +`; + +const BottomBackground = styled.div` + background: url('https://mdn.alipayobjects.com/huamei_xgb3qj/afts/img/A*umu0Q6JaXs8AAAAAAAAAAAAADtmcAQ/original') + no-repeat; + background-size: cover; + background-position: center; +`; + const MainPage = () => { const { Messages: { - COPYRIGHT_INFORMATION_CONFIG, + TITLE, + COOPERATION_PARTNER, PARAGRAPH, - SPG_CASE_CONFIG, - SPG_POINT_CONFIG, + BUSINESS_APPLICATIONS, + TECHNICAL_FEATURES, }, } = useIntl(); - const locale = useLocale(); const [prefersColor] = usePrefersColor(); - const push = (link: string) => { - // @ts-ignore - const base = locale.base; - if (base === '/') history.push(`/${link}`); - else history.push(`${base}/${link}`); - }; - useEffect(() => { const main = document.querySelector('body .dumi-default-doc-layout > main'); - main && - main.setAttribute( - 'style', - 'margin-top: -76px; padding: 0; max-width: 100%;', - ); + main && main.setAttribute('style', 'padding: 0; max-width: 100%;'); return () => { main && @@ -321,122 +217,89 @@ const MainPage = () => { }; }, []); - const handleDownload = () => { - push('download'); - }; - return ( -
+ + + + + + + - - - - <div>语义增强可编程知识图谱SPG</div> - <div>(Semantic-enhanced Programmable Graph)</div> - - - - - - - + + {TITLE.abbr} + · + {TITLE.full} + + {TITLE.sub} - - - {PARAGRAPH.whyChooseSPG} - - {SPG_POINT_CONFIG.map((item) => { + + + + + + + + {PARAGRAPH.TechnicalFeatures} + + + {TECHNICAL_FEATURES.map((item) => { return ; })} - - - - - - {PARAGRAPH.SPGFeaturesSemanticExamples} - {PARAGRAPH.DeepSemanticNetworking} + + + + + + + {PARAGRAPH.BusinessApplications} + + + - ), - }, - { - key: '2', - label: PARAGRAPH.DataToKnowledgeProcess, - children: , - }, - ]} + items={BUSINESS_APPLICATIONS.map((item, index) => ({ + key: `${index}`, + label: item.title, + children: ( + + ), + }))} /> - - - - - {PARAGRAPH.SPGSemanticFramework} - {PARAGRAPH.AccelerateDataIntegration} - - - - - - {PARAGRAPH.SPGCaseStudies} - {SPG_CASE_CONFIG.map((item, index) => { - return ( - - ); - })} - - -
- -
- - - {COPYRIGHT_INFORMATION_CONFIG.map((item) => { - return ( - - {item.unitNames.map((unit) => { - return ( - {unit} - ); - })} - - ); - })} - - - -
+ + + + + + + {PARAGRAPH.CooperationPartner} + + + {COOPERATION_PARTNER.map((item) => { + return ( + + {item.unitNames.map((unit) => { + return ( + {unit} + ); + })} + + ); + })} + + + + + +
); }; diff --git a/.dumi/theme/layouts/GlobalLayout.tsx b/.dumi/theme/layouts/GlobalLayout.tsx index 074a09d..5bcb2ac 100644 --- a/.dumi/theme/layouts/GlobalLayout.tsx +++ b/.dumi/theme/layouts/GlobalLayout.tsx @@ -2,6 +2,7 @@ import { ConfigProvider, Result, theme, Modal } from 'antd'; import { useOutlet, usePrefersColor } from 'dumi'; import React, { useState, useEffect } from 'react'; import { useIntl } from '../../hooks/useIntl'; +import { PREFIX } from '../../constants/prefix'; import { isMobile as isMobileDevice } from 'react-device-detect'; // insert github and openKG in navbar @@ -92,10 +93,15 @@ const GlobalLayout: React.FC = () => { return (