diff --git a/package-lock.json b/package-lock.json index e8055adbd..e2b53a317 100644 --- a/package-lock.json +++ b/package-lock.json @@ -28,6 +28,7 @@ "cookies-next": "^2.0.3", "core-js": "3.6.5", "cross-env": "^7.0.2", + "css-doodle": "^0.21.6", "express": "^4.16.4", "glob": "^7.1.2", "graphql": "^15.5.1", @@ -7540,6 +7541,15 @@ "node": ">=4" } }, + "node_modules/css-doodle": { + "version": "0.21.6", + "resolved": "https://registry.npmjs.org/css-doodle/-/css-doodle-0.21.6.tgz", + "integrity": "sha512-w9cZpmGH7OC/ufe0GHnqPS4kVXlEV7gj9RaLnqbxwIIEFN+pHckS/U9nnClHESWv0RaYcNhFItWc6xAyR0/Nxw==", + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/css-doodle" + } + }, "node_modules/css-in-js-utils": { "version": "2.0.1", "integrity": "sha512-PJF0SpJT+WdbVVt0AOYp9C8GnuruRlL/UFW7932nLWmFLQTaWEzTBQEx7/hn4BuV+WON75iAViSUJLiU3PKbpA==", @@ -29263,6 +29273,11 @@ "version": "1.0.0", "integrity": "sha1-/qJhbcZ2spYmhrOvjb2+GAskTgU=" }, + "css-doodle": { + "version": "0.21.6", + "resolved": "https://registry.npmjs.org/css-doodle/-/css-doodle-0.21.6.tgz", + "integrity": "sha512-w9cZpmGH7OC/ufe0GHnqPS4kVXlEV7gj9RaLnqbxwIIEFN+pHckS/U9nnClHESWv0RaYcNhFItWc6xAyR0/Nxw==" + }, "css-in-js-utils": { "version": "2.0.1", "integrity": "sha512-PJF0SpJT+WdbVVt0AOYp9C8GnuruRlL/UFW7932nLWmFLQTaWEzTBQEx7/hn4BuV+WON75iAViSUJLiU3PKbpA==", diff --git a/package.json b/package.json index 9ee7d2874..3ee10d4ca 100644 --- a/package.json +++ b/package.json @@ -60,6 +60,7 @@ "cookies-next": "^2.0.3", "core-js": "3.6.5", "cross-env": "^7.0.2", + "css-doodle": "^0.21.6", "express": "^4.16.4", "glob": "^7.1.2", "graphql": "^15.5.1", diff --git a/src/containers/content/HaveADrinkContent/Body/Content.tsx b/src/containers/content/HaveADrinkContent/Body/Content.tsx index fc2f462ca..b0e44cd23 100644 --- a/src/containers/content/HaveADrinkContent/Body/Content.tsx +++ b/src/containers/content/HaveADrinkContent/Body/Content.tsx @@ -25,7 +25,7 @@ const Content: FC = ({ item }) => { return ( - + {refLink && } {item.text} diff --git a/src/containers/content/HaveADrinkContent/demo.ts b/src/containers/content/HaveADrinkContent/demo.ts index d7d800f02..930176eaf 100644 --- a/src/containers/content/HaveADrinkContent/demo.ts +++ b/src/containers/content/HaveADrinkContent/demo.ts @@ -14,17 +14,24 @@ const demo = [ images: [], }, { - text: 'CoderPlanets 成员在不同的子社区有不同的昵称,比如在首页叫 CPer,在 Elixir 社区叫 Alchemist, 在 Rust 社区叫 Rustacean 等等。', + text: 'CoderPlanets 的用户在不同子社区中有对应的昵称,比如在首页叫 CPer,在 Elixir 社区叫 Alchemist, 在 Rust 社区叫 Rustacean 等等。', + reference: 'https://coderplanets.com/elixir', }, { text: 'CoderPlanets 评论表情包中的感谢概念,是一个由爱心抽象出来的大螃蟹钳子,谐音为「谢谢」。', + images: [`${ASSETS_ENDPOINT}/ugc/tmp/drink-crabheart.png`], + imageSize: 'small', }, { - text: 'CoderPlanets 的分享模块,除了常见的第三方社交平台,还有程序员常用的 MD, 以及 Org-Mode 格式。', + text: 'CoderPlanets 中的链接分享,除了常见的第三方社交平台,还有程序员常用的 Markdown,Org-Mode 等格式。', }, { text: 'CoderPlanets 遵循中文排版原则,后端会自动为中英文间插入空格,中文的引号转义为「」等等。', }, + { + text: 'CoderPlanets 会员升级页面的招呼「你好哇」,来自「程序员」王小波给李银河的情书集 —《爱你就像爱生命》。', + reference: 'https://coderplanets.com/membership', + }, { text: 'CoderPlanets 的前端没有使用任何流行的「UI 组件库」,几乎所有组件都是量身定制,基本上没有撞衫的可能。', }, diff --git a/src/containers/content/HaveADrinkContent/spec.ts b/src/containers/content/HaveADrinkContent/spec.ts index 7117223df..2c6b3cc3d 100644 --- a/src/containers/content/HaveADrinkContent/spec.ts +++ b/src/containers/content/HaveADrinkContent/spec.ts @@ -14,6 +14,7 @@ export type TDrinkItem = { text: string reference?: string images?: string[] + imageSize?: string } export type TDrinkCategory = { diff --git a/src/containers/content/HaveADrinkContent/styles/body/content.ts b/src/containers/content/HaveADrinkContent/styles/body/content.ts index 9f9cc4336..fa7a31ccb 100644 --- a/src/containers/content/HaveADrinkContent/styles/body/content.ts +++ b/src/containers/content/HaveADrinkContent/styles/body/content.ts @@ -25,8 +25,8 @@ export const ImageContentWrapper = styled(Wrapper)` ${css.flexColumn('align-both')} margin-top: -30px; ` -export const Image = styled(Img)` - height: 200px; +export const Image = styled(Img)<{ size: string }>` + height: ${({ size }) => (size === 'small' ? '60px' : '200px')}; object-fit: cover; border-radius: 8px; ` diff --git a/src/containers/content/SponsorContent/Banner.js b/src/containers/content/SponsorContent/Banner.tsx similarity index 78% rename from src/containers/content/SponsorContent/Banner.js rename to src/containers/content/SponsorContent/Banner.tsx index bf4f6afdf..bda84d42a 100644 --- a/src/containers/content/SponsorContent/Banner.js +++ b/src/containers/content/SponsorContent/Banner.tsx @@ -6,7 +6,8 @@ * */ -import React, { useState } from 'react' +import { FC, memo, useState, Fragment } from 'react' +import Link from 'next/link' import { buildLog } from '@/utils/logger' import ViewportTracker from '@/widgets/ViewportTracker' @@ -27,7 +28,7 @@ import { toggleBannerVisiable } from './logic' /* eslint-disable-next-line */ const log = buildLog('C:SponsorContent') -const Banner = () => { +const Banner: FC = () => { const [anchorHEnter, setAnchorHEnter] = useState(false) const [anchorMEnter, setAnchorMEnter] = useState(false) const [anchorLEnter, setAnchorLEnter] = useState(false) @@ -40,7 +41,7 @@ const Banner = () => { } return ( - + setAnchorHEnter(true)} @@ -73,16 +74,18 @@ const Banner = () => { 2020 - 感谢以下团队、个人对本站的特别赞助 + 感谢以下团队、个人对本项目的特别赞助 {anchorMEnter && ( - - 我要赞助 - + + + 我要赞助 + + )} {!anchorMEnter && } - + ) } -export default Banner +export default memo(Banner) diff --git a/src/containers/content/SponsorContent/SponsorTypeTitle.js b/src/containers/content/SponsorContent/SponsorTypeTitle.tsx similarity index 56% rename from src/containers/content/SponsorContent/SponsorTypeTitle.js rename to src/containers/content/SponsorContent/SponsorTypeTitle.tsx index 9c0078bd9..f80838a1e 100644 --- a/src/containers/content/SponsorContent/SponsorTypeTitle.js +++ b/src/containers/content/SponsorContent/SponsorTypeTitle.tsx @@ -1,11 +1,15 @@ -import React from 'react' -import T from 'prop-types' +import { FC, memo } from 'react' import { ICON } from '@/config' import { Wrapper, Title, PrefixIcon } from './styles/sponsor_type_title' -const SponsorTitle = ({ title, type }) => { +type TProps = { + title: string + type?: string +} + +const SponsorTitle: FC = ({ title, type = 'gold' }) => { const iconSrc = type === 'gold' ? `${ICON}/shape/wing.svg` : `${ICON}/shape/candy.svg` @@ -18,13 +22,4 @@ const SponsorTitle = ({ title, type }) => { ) } -SponsorTitle.propTypes = { - type: T.oneOf(['gold', 'heart']), - title: T.string.isRequired, -} - -SponsorTitle.defaultProps = { - type: 'gold', -} - -export default React.memo(SponsorTitle) +export default memo(SponsorTitle) diff --git a/src/containers/content/SponsorContent/index.tsx b/src/containers/content/SponsorContent/index.tsx index e0b85c741..86c25eac8 100755 --- a/src/containers/content/SponsorContent/index.tsx +++ b/src/containers/content/SponsorContent/index.tsx @@ -21,7 +21,14 @@ import type { TStore } from './store' import Banner from './Banner' import SponsorTypeTitle from './SponsorTypeTitle' -import { Wrapper, InnerWrapper, ContentWrapper, Footer } from './styles' +import { + Wrapper, + InnerWrapper, + ContentWrapper, + DonateTitle, + DonateWrapper, + DonateAvatar, +} from './styles' import { useInit } from './logic' /* eslint-disable-next-line */ @@ -30,79 +37,54 @@ const log = buildLog('C:SponsorContent') const goldItems = [ { id: '0', - addr: 'xxx.com', - title: 'javascript', - desc: '最性感的开发者社区', - level: 'gold', - icon: 'https://cps-oss.oss-cn-shanghai.aliyuncs.com/icons/pl/javascript.png', + addr: 'https://your-brand.com', + title: '空缺中', + desc: '赞助后你的品牌同时将出现在这里以及本项目的 Github 主页。', }, { id: '1', - addr: 'elixir.com', - title: 'elixir', - desc: '最性感的开发者社区', - level: 'gold', - icon: 'https://cps-oss.oss-cn-shanghai.aliyuncs.com/icons/pl/elixir.png', + addr: 'https://your-brand.com', + title: '空缺中', + desc: '赞助后你的品牌同时将出现在这里以及本项目的 Github 主页。', }, { id: '2', - addr: 'clojure-lang.com', - title: 'clojure', - desc: '最性感的开发者社区少数派致力于更好地运用数字产品或科学方法,帮助用户提升工作效率和生活品质.', - level: 'gold', - icon: 'https://cps-oss.oss-cn-shanghai.aliyuncs.com/icons/pl/clojure.png', + addr: 'https://your-brand.com', + title: '空缺中', + desc: '赞助后你的品牌同时将出现在这里以及本项目的 Github 主页。', }, -] - -const items = [ { id: '3', - addr: 'javascript.com', - title: 'Teambition', - desc: '一切工作都可以从Teambition开始。无论是策划活动、研发软件、制造机器人、建设发电站或者发射卫星,团队成员以更高效的协作方式,为目标不断创造成果。', - icon: 'https://cps-oss.oss-cn-shanghai.aliyuncs.com/icons/pl/javascript.png', - }, - { - id: '4', - addr: 'sspai.com', - title: '少数派', - desc: '少数派致力于更好地运用数字产品或科学方法,帮助用户提升工作效率和生活品质.', - icon: 'https://cps-oss.oss-cn-shanghai.aliyuncs.com/editor/embeds/shaoshupai.png', - }, - { - id: '5', - addr: 'whatthefuck.com', - title: 'whatever', - desc: '一切工作都可以从Teambition开始。无论是策划活动、研发软件、制造机器人、建设发电站或者发射卫星,团队成员以更高效的协作方式,为目标不断创造成果。', - icon: 'https://cps-oss.oss-cn-shanghai.aliyuncs.com/icons/pl/clojure.png', + addr: 'https://your-brand.com', + title: '空缺中', + desc: '赞助后你的品牌同时将出现在这里以及本项目的 Github 主页。', }, +] + +const items = [ { - id: '6', - addr: 'javascript.com', - title: 'Teambition', - desc: '一切工作都可以从Teambition开始。无论是策划活动、研发软件、制造机器人、建设发电站或者发射卫星,团队成员以更高效的协作方式,为目标不断创造成果。', - icon: 'https://cps-oss.oss-cn-shanghai.aliyuncs.com/icons/pl/javascript.png', + id: '0', + addr: 'https://your-brand.com', + title: '空缺中', + desc: '赞助后你的品牌同时将出现在这里以及本项目的 Github 主页。', }, { - id: '7', - addr: 'sspai.com', - title: '少数派', - desc: '少数派致力于更好地运用数字产品或科学方法,帮助用户提升工作效率和生活品质.', - icon: 'https://cps-oss.oss-cn-shanghai.aliyuncs.com/editor/embeds/shaoshupai.png', + id: '1', + addr: 'https://your-brand.com', + title: '空缺中', + desc: '赞助后你的品牌同时将出现在这里以及本项目的 Github 主页。', }, { - id: '8', - addr: 'whatthefuck.com', - title: 'whatever', - desc: '最性感的开发者社区', - icon: 'https://cps-oss.oss-cn-shanghai.aliyuncs.com/icons/pl/clojure.png', + id: '2', + addr: 'https://your-brand.com', + title: '空缺中', + desc: '赞助后你的品牌同时将出现在这里以及本项目的 Github 主页。', }, { - id: '9', - addr: 'sspai.com', - title: '少数派', - desc: '少数派致力于更好地运用数字产品或科学方法,帮助用户提升工作效率和生活品质.', - icon: 'https://cps-oss.oss-cn-shanghai.aliyuncs.com/editor/embeds/shaoshupai.png', + id: '3', + addr: 'https://your-brand.com', + title: '空缺中', + desc: '赞助后你的品牌同时将出现在这里以及本项目的 Github 主页。', }, ] @@ -126,15 +108,24 @@ const SponsorContentContainer: FC = ({
- -
- + +
+ - +
- +
-
以上名单按投放时间排序
+ 感谢各位好心人热心打赏 + + t + h + a + n + k + s + ! +
) diff --git a/src/containers/content/SponsorContent/logic.js b/src/containers/content/SponsorContent/logic.ts old mode 100755 new mode 100644 similarity index 68% rename from src/containers/content/SponsorContent/logic.js rename to src/containers/content/SponsorContent/logic.ts index e0593d031..af93f2480 --- a/src/containers/content/SponsorContent/logic.js +++ b/src/containers/content/SponsorContent/logic.ts @@ -1,21 +1,24 @@ import { useEffect } from 'react' import { buildLog } from '@/utils/logger' + +import type { TStore } from './store' // import S from './service' -let store = null +let store: TStore | undefined /* eslint-disable-next-line */ const log = buildLog('L:SponsorContent') -export const toggleBannerVisiable = (bannerVisiable) => +export const toggleBannerVisiable = (bannerVisiable: boolean): void => { store.mark({ bannerVisiable }) +} // ############################### // init & uninit handlers // ############################### -export const useInit = (_store) => { +export const useInit = (_store: TStore): void => { useEffect(() => { store = _store log('useInit: ', store) diff --git a/src/containers/content/SponsorContent/styles/banner.ts b/src/containers/content/SponsorContent/styles/banner.ts index 1c76c68a1..8db7acadb 100644 --- a/src/containers/content/SponsorContent/styles/banner.ts +++ b/src/containers/content/SponsorContent/styles/banner.ts @@ -4,7 +4,6 @@ import type { TActive } from '@/spec' import { theme } from '@/utils/themes' import css from '@/utils/css' -import ArrowLink from '@/widgets/Buttons/ArrowLink' import Img from '@/Img' import { getBorderRadius, getBannerHeight, getBackground } from './metric' @@ -15,7 +14,7 @@ type TAnchors = { anchorMEnter: boolean anchorLEnter: boolean } - reverse: boolean + reverse?: boolean } export const SmileWrapper = styled.div` @@ -68,12 +67,18 @@ export const AnchorM = styled(Anchor)` export const AnchorL = styled(Anchor)` top: 80px; ` -export const SponsorBtn = styled(ArrowLink)` - margin-left: 20px; +export const SponsorBtn = styled.a` + font-size: 18px; + color: ${theme('button.primary')}; + text-decoration: none; opacity: ${({ show }) => (show ? '1' : '0')}; transition: opacity 0.25s; transition-delay: 0.4s; + + &:hover { + text-decoration: none; + } ` export const Divider = styled.div` margin-top: 10px; diff --git a/src/containers/content/SponsorContent/styles/index.ts b/src/containers/content/SponsorContent/styles/index.ts index 17cf4acc0..a02ddfb0e 100755 --- a/src/containers/content/SponsorContent/styles/index.ts +++ b/src/containers/content/SponsorContent/styles/index.ts @@ -25,8 +25,8 @@ export const ContentWrapper = styled.div<{ metric: TMetric }>` ${css.flexColumn('align-center')}; ${({ metric }) => css.fitContentWidth(metric)}; ` -export const Footer = styled.div` - font-size: 13px; +export const DonateTitle = styled.div` + font-size: 14px; color: ${theme('thread.articleDigest')}; opacity: 0.8; margin-top: 50px; @@ -39,3 +39,15 @@ export const Footer = styled.div` margin-left: 8px; } ` +export const DonateWrapper = styled.div` + ${css.flex('justify-center')}; + margin-top: 40px; +` +export const DonateAvatar = styled.div` + color: ${theme('thread.articleDigest')}; + ${css.circle(30)}; + ${css.flex('align-both')}; + margin-right: 15px; + margin-bottom: 15px; + background: #0c3744; +` diff --git a/src/containers/content/SponsorContent/styles/metric.js b/src/containers/content/SponsorContent/styles/metric.ts similarity index 78% rename from src/containers/content/SponsorContent/styles/metric.js rename to src/containers/content/SponsorContent/styles/metric.ts index 689923abe..8f2abfb2a 100644 --- a/src/containers/content/SponsorContent/styles/metric.js +++ b/src/containers/content/SponsorContent/styles/metric.ts @@ -1,7 +1,7 @@ import { theme } from '@/utils/themes' // see details in https://9elements.github.io/fancy-border-radius/ -export const getBorderRadius = (anchors) => { +export const getBorderRadius = (anchors): string => { const { anchorHEnter, anchorMEnter } = anchors if (anchorHEnter) return '0% 100% 49% 51% / 57% 0% 100% 43%' @@ -10,7 +10,7 @@ export const getBorderRadius = (anchors) => { return '100% 0% 49% 51% / 100% 100% 0% 0%' } -export const getBannerHeight = (anchors) => { +export const getBannerHeight = (anchors): string => { const { anchorMEnter, anchorLEnter } = anchors if (!anchorLEnter) return '20vh' if (!anchorMEnter) return '30vh' @@ -18,7 +18,7 @@ export const getBannerHeight = (anchors) => { return '40vh' } -export const getBackground = (anchors) => { +export const getBackground = (anchors): string => { const { anchorMEnter } = anchors if (!anchorMEnter) return 'transparent' diff --git a/src/containers/content/SponsorContent/styles/sponsor_type_title.ts b/src/containers/content/SponsorContent/styles/sponsor_type_title.ts index a031e4b66..a9797b905 100644 --- a/src/containers/content/SponsorContent/styles/sponsor_type_title.ts +++ b/src/containers/content/SponsorContent/styles/sponsor_type_title.ts @@ -16,7 +16,7 @@ export const Title = styled.div` margin-left: 10px; margin-right: 10px; ` -export const PrefixIcon = styled(Img)<{ reverse: boolean }>` +export const PrefixIcon = styled(Img)<{ reverse?: boolean }>` fill: ${theme('thread.articleDigest')}; ${css.size(15)}; diff --git a/src/pages/sponsor.tsx b/src/pages/sponsor.tsx index e9dd1b6cc..dd9beec44 100755 --- a/src/pages/sponsor.tsx +++ b/src/pages/sponsor.tsx @@ -1,3 +1,4 @@ +import { GetServerSideProps } from 'next' import { Provider } from 'mobx-react' import { METRIC } from '@/constant' @@ -5,50 +6,43 @@ import { METRIC } from '@/constant' import { ssrBaseStates, ssrFetchPrepare, - ssrRescue, + refreshIfneed, sponsorSEO, ssrError, } from '@/utils' + import { P } from '@/schemas' import GlobalLayout from '@/containers/layout/GlobalLayout' import SponsorContent from '@/containers/content/SponsorContent' import { useStore } from '@/stores/init' -const fetchData = async (props, opt = {}) => { +const fetchData = async (context, opt = {}) => { const { gqClient } = ssrFetchPrepare(context, opt) - const sessionState = gqClient.request(P.sessionState) - const subscribedCommunities = gqClient.request(P.subscribedCommunities, { - filter: { - page: 1, - size: 30, - }, - }) return { ...(await sessionState), - ...(await subscribedCommunities), } } -export const getServerSideProps = async (context) => { +export const getServerSideProps: GetServerSideProps = async (context) => { let resp try { resp = await fetchData(context) - } catch ({ response: { errors } }) { - if (ssrRescue.hasLoginError(errors)) { - resp = await fetchData(context, { tokenExpired: true }) - } else { - return ssrError(context, 'fetch', 500) - } - } + const { sessionState } = resp - const initProps = { ...ssrBaseStates(resp) } + refreshIfneed(sessionState, '/trending', context) + } catch (e) { + console.log('#### error from server: ', e) + return ssrError(context, 'fetch', 500) + } - return { - props: { errorCode: null, namespacesRequired: ['general'], ...initProps }, + const initProps = { + ...ssrBaseStates(resp), } + + return { props: { errorCode: null, ...initProps } } } const SponsorPage = (props) => { diff --git a/src/widgets/GalleryHub/SponsorGallery.js b/src/widgets/GalleryHub/SponsorGallery.js deleted file mode 100755 index d7e7360fd..000000000 --- a/src/widgets/GalleryHub/SponsorGallery.js +++ /dev/null @@ -1,149 +0,0 @@ -/* - * - * SponsorGallery - * - */ - -import React from 'react' -import T from 'prop-types' - -import { ASSETS_ENDPOINT } from '@/config' -import { cutRest } from '@/utils/helper' -import { buildLog } from '@/utils/logger' - -import ArrowButton from '@/widgets/Buttons/ArrowButton' - -import { - Wrapper, - Block, - Header, - IntroHead, - Icon, - Title, - IntroImg, - Desc, - LinkWrapper, -} from './styles/sponsor_gallery' - -/* eslint-disable-next-line */ -const log = buildLog('c:SponsorGallery:index') - -const tmpItems = [ - { - id: '0', - addr: 'xxx.com', - title: 'javascript', - desc: '最性感的开发者社区', - level: 'gold', - icon: 'https://cps-oss.oss-cn-shanghai.aliyuncs.com/icons/pl/javascript.png', - }, - { - id: '1', - addr: 'elixir.com', - title: 'elixir', - desc: '最性感的开发者社区', - level: 'gold', - icon: 'https://cps-oss.oss-cn-shanghai.aliyuncs.com/icons/pl/elixir.png', - }, - { - id: '2', - addr: 'clojure-lang.com', - title: 'clojure', - desc: '最性感的开发者社区少数派致力于更好地运用数字产品或科学方法,帮助用户提升工作效率和生活品质.', - level: 'gold', - icon: 'https://cps-oss.oss-cn-shanghai.aliyuncs.com/icons/pl/clojure.png', - }, - { - id: '3', - addr: 'javascript.com', - title: 'Teambition', - desc: '一切工作都可以从Teambition开始。无论是策划活动、研发软件、制造机器人、建设发电站或者发射卫星,团队成员以更高效的协作方式,为目标不断创造成果。', - icon: 'https://cps-oss.oss-cn-shanghai.aliyuncs.com/icons/pl/javascript.png', - }, - { - id: '4', - addr: 'sspai.com', - title: '少数派', - desc: '少数派致力于更好地运用数字产品或科学方法,帮助用户提升工作效率和生活品质.', - icon: 'https://cps-oss.oss-cn-shanghai.aliyuncs.com/editor/embeds/shaoshupai.png', - }, - { - id: '5', - addr: 'whatthefuck.com', - title: 'whatever', - desc: '一切工作都可以从Teambition开始。无论是策划活动、研发软件、制造机器人、建设发电站或者发射卫星,团队成员以更高效的协作方式,为目标不断创造成果。', - icon: 'https://cps-oss.oss-cn-shanghai.aliyuncs.com/icons/pl/clojure.png', - }, - { - id: '6', - addr: 'javascript.com', - title: 'Teambition', - desc: '一切工作都可以从Teambition开始。无论是策划活动、研发软件、制造机器人、建设发电站或者发射卫星,团队成员以更高效的协作方式,为目标不断创造成果。', - icon: 'https://cps-oss.oss-cn-shanghai.aliyuncs.com/icons/pl/javascript.png', - }, - { - id: '7', - addr: 'sspai.com', - title: '少数派', - desc: '少数派致力于更好地运用数字产品或科学方法,帮助用户提升工作效率和生活品质.', - icon: 'https://cps-oss.oss-cn-shanghai.aliyuncs.com/editor/embeds/shaoshupai.png', - }, - { - id: '8', - addr: 'whatthefuck.com', - title: 'whatever', - desc: '最性感的开发者社区', - icon: 'https://cps-oss.oss-cn-shanghai.aliyuncs.com/icons/pl/clojure.png', - }, - { - id: '9', - addr: 'sspai.com', - title: '少数派', - desc: '少数派致力于更好地运用数字产品或科学方法,帮助用户提升工作效率和生活品质.', - icon: 'https://cps-oss.oss-cn-shanghai.aliyuncs.com/editor/embeds/shaoshupai.png', - }, -] - -const SponsorGallery = ({ items, column }) => { - return ( - - {items.map((item, index) => ( - -
- - {item.title} - - -
- {item.level === 'gold' && ( - - )} - {item.desc && ( - {cutRest(item.desc, 30)} - )} - - {item.addr} - -
- ))} -
- ) -} - -SponsorGallery.propTypes = { - items: T.arrayOf(T.object), - column: T.oneOf([3, 4]), -} - -SponsorGallery.defaultProps = { - items: tmpItems, - column: 3, -} - -export default React.memo(SponsorGallery) diff --git a/src/widgets/GalleryHub/SponsorGallery/Patterns.tsx b/src/widgets/GalleryHub/SponsorGallery/Patterns.tsx new file mode 100644 index 000000000..94ef6182b --- /dev/null +++ b/src/widgets/GalleryHub/SponsorGallery/Patterns.tsx @@ -0,0 +1,88 @@ +import { FC, memo, useCallback, useRef } from 'react' + +import { getRandomInt } from '@/utils/helper' +import { useInterval } from '@/hooks' +import 'css-doodle' + +import { Wrapper, Block } from '../styles/sponsor_gallery/patterns' + +const Rules = { + 0: ` + :doodle { + @grid: 24 / 35vw 250px; + overflow: hidden; + } + :after { + content: '\\@hex(@rand(9632, 9687))'; + color: @pick(#395e75, #358478, #18657E, #2C77A3); + font-size: 24px; + } + `, + 1: ` + :doodle { + @grid: 24 / 35vw 250px; + grid-gap: 6px; + overflow: hidden; + } + :after { + content: '\\@pick(0043, 0050, 706b, 006e, 5fc3, 4e2d, 0416, 0A09)'; + color: @pick(#395e75, #358478, #18657E, #2C77A3); + font-size: 24px; + transform: scale(@rand(.2,1.8)); + } + `, + 2: ` + :doodle { + @grid: 24 / 35vw 250px; + overflow: hidden; + } + :after { + content: '\\@hex(@rand(0x2500, 0x257f))'; + color: @pick(#395e75, #358478, #18657E, #2C77A3); + font-size: 24px; + } + `, + 3: ` + :doodle { + @grid: 24 / 35vw 250px; + grid-gap: 3px; + overflow: hidden; + } + :after { + content: '\\@pick(2686, 2687, 2688, 2689)'; + color: @pick(#395e75, #358478, #18657E, #2C77A3); + font-size: 24px; + transform: scale(@rand(.2,2)); + } + `, +} + +type TProps = { + index: number +} + +const Patterns: FC = ({ index }) => { + const ref = useRef(null) + + const changePattern = useCallback(() => { + if (ref?.current) { + const doodle = ref?.current.querySelector('css-doodle') + doodle.update() + } + }, [ref]) + + useInterval(() => { + changePattern() + }, getRandomInt(4, 12) * 1000) + + return ( + + + {/* @ts-ignore */} + {Rules[index]} + + + ) +} + +export default memo(Patterns) diff --git a/src/widgets/GalleryHub/SponsorGallery/index.tsx b/src/widgets/GalleryHub/SponsorGallery/index.tsx new file mode 100644 index 000000000..eeabf9eab --- /dev/null +++ b/src/widgets/GalleryHub/SponsorGallery/index.tsx @@ -0,0 +1,72 @@ +/* + * + * SponsorGallery + * + */ + +import { FC, memo } from 'react' +import dynamic from 'next/dynamic' + +import { cutRest } from '@/utils/helper' +import { buildLog } from '@/utils/logger' + +import Linker from '@/widgets/Linker' + +import { + Wrapper, + Block, + Header, + IntroHead, + Icon, + Title, + IntroImg, + Desc, + LinkWrapper, +} from '../styles/sponsor_gallery' + +/* eslint-disable-next-line */ +const log = buildLog('c:SponsorGallery:index') + +const Patterns = dynamic(() => import('./Patterns'), { + /* eslint-disable react/display-name */ + // loading: () => 心爱的作品, + ssr: false, +}) + +type TProps = { + items: { + id: string + title: string + addr: string + desc: string + icon?: string + }[] + level?: 'gold' | 'silver' +} + +const SponsorGallery: FC = ({ items, level = 'gold' }) => { + return ( + + {items.map((item, index) => ( + +
+ + {item.title} + {level === 'silver' && } + +
+ {level === 'gold' && ( + + // + )} + {item.desc && {cutRest(item.desc, 30)}} + + + +
+ ))} +
+ ) +} + +export default memo(SponsorGallery) diff --git a/src/widgets/GalleryHub/styles/sponsor_gallery.ts b/src/widgets/GalleryHub/styles/sponsor_gallery/index.ts old mode 100755 new mode 100644 similarity index 88% rename from src/widgets/GalleryHub/styles/sponsor_gallery.ts rename to src/widgets/GalleryHub/styles/sponsor_gallery/index.ts index 5645c0fc6..c7eb52494 --- a/src/widgets/GalleryHub/styles/sponsor_gallery.ts +++ b/src/widgets/GalleryHub/styles/sponsor_gallery/index.ts @@ -11,14 +11,12 @@ export const Wrapper = styled.div<{ center: boolean }>` color: ${theme('thread.articleDigest')}; width: 100%; ` -type TBlock = { level: string; column: number } +type TBlock = { level: string } export const Block = styled.div` ${css.flexColumn('justify-between')}; - width: ${({ column }) => (column === 3 ? '33%' : '25%')}; + width: ${({ level }) => (level === 'gold' ? '20%' : '25%')}; height: ${({ level }) => (level === 'gold' ? '280px' : '130px')}; - border: none; padding: ${({ level }) => (level === 'gold' ? '25px 25px' : '18px 25px')}; - border-radius: 2px; border: 1px solid transparent; margin-bottom: ${({ level }) => (level === 'gold' ? '20px' : '10px')}; @@ -45,8 +43,10 @@ export const IntroHead = styled.div` cursor: pointer; } ` -export const Icon = styled(Img)` - ${css.circle(20)}; +export const Icon = styled.div` + ${css.size(20)}; + background: #024b59; + border-radius: 4px; ` export const Title = styled.div<{ level: string }>` color: ${theme('thread.articleTitle')}; @@ -63,6 +63,11 @@ export const Title = styled.div<{ level: string }>` transition: all 0.2s; transition-delay: 0.2s; ` +export const IntroGoldHolder = styled.div` + background: #003a47; + width: 100%; + height: 100px; +` export const IntroImg = styled(Img)` width: 100%; height: 100px; diff --git a/src/widgets/GalleryHub/styles/sponsor_gallery/patterns.ts b/src/widgets/GalleryHub/styles/sponsor_gallery/patterns.ts new file mode 100644 index 000000000..833155f76 --- /dev/null +++ b/src/widgets/GalleryHub/styles/sponsor_gallery/patterns.ts @@ -0,0 +1,16 @@ +import styled from 'styled-components' + +// import css from '@/utils/css' + +export const Wrapper = styled.div` + width: 100%; + margin-top: 10px; + margin-bottom: 10px; + filter: saturate(0.8); + opacity: 0.8; +` +export const Block = styled.div` + height: 100px; + width: 240px; + overflow: hidden; +` diff --git a/src/widgets/Modal/Belt.js b/src/widgets/Modal/Belt.js deleted file mode 100755 index fd4eb53f4..000000000 --- a/src/widgets/Modal/Belt.js +++ /dev/null @@ -1,41 +0,0 @@ -import React from 'react' - -import useScript from '@/hooks/useScript' - -import { Wrapper, Holder } from './styles/belt' - -const Belt = () => { - const [loaded] = useScript( - 'https://unpkg.com/css-doodle@0.7.7/css-doodle.min.js', - ) - // 电路图效果 - // content: '\\@hex(@rand(0x2500, 0x257f))'; - // 圈圈圆圆三角效果 - // content: \\@hex(@rand(9632, 9687)); - // 杂乱效果 - // content: '\\@pick(27d4, 21b0, 141b, 141d, 2686, 1401, 2688, 2689)'; - const rule = ` - :doodle { - @grid: 24 / 35vw 250px; - overflow: hidden; - } - :after { - content: '\\@hex(@rand(0x2500, 0x257f))'; - color: @pick(#395e75, #358478, #18657E, #2C77A3); - font-size: 24px; - } - ` - return ( - <> - {loaded && ( - - {rule} - - {rule} - - )} - - ) -} - -export default React.memo(Belt) diff --git a/src/widgets/Modal/index.tsx b/src/widgets/Modal/index.tsx index 1191462ae..536f59027 100755 --- a/src/widgets/Modal/index.tsx +++ b/src/widgets/Modal/index.tsx @@ -7,13 +7,11 @@ import { FC, ReactNode, useEffect, useState, useCallback, memo } from 'react' import usePortal from 'react-useportal' -import { ICON_CMD } from '@/config' import { toggleGlobalBlur } from '@/utils/dom' import { buildLog } from '@/utils/logger' import useShortcut from '@/hooks/useShortcut' import ViewportTracker from '@/widgets/ViewportTracker' -import Belt from './Belt' import { Mask, Wrapper, CloseBtn, EscHint, ChildrenWrapper } from './styles' @@ -69,7 +67,6 @@ const Modal: FC = ({ {show && ( - {showBelt && }