From 02b0ebc9e11e357f6ea953f4cd8304a95e900e63 Mon Sep 17 00:00:00 2001 From: HesterG Date: Fri, 21 Jul 2023 10:57:22 +0000 Subject: [PATCH] Add subscription and community components (#47) Close #46 Same as those in [blog](https://gitea.com/gitea/blog/pulls/272), but for docs and api Ejected DocPage (unsafe to eject) and ApiDoc (safe to eject) for layout changes ![Screen Shot 2023-07-17 at 15.32.29](/attachments/74f992c7-b60d-4d71-bb50-8c085e6783fe)![Screen Shot 2023-07-17 at 15.32.40](/attachments/0df35cba-0797-4f21-abbe-bb61736c1e1f) Screenshots ![Screen Shot 2023-07-17 at 15.27.29](/attachments/39e09cee-5043-4349-aaaa-7ab585aefbc4)![Screen Shot 2023-07-17 at 15.27.36](/attachments/396a9ae1-bbae-42b5-b1ab-c4158a2be78d)![Screen Shot 2023-07-17 at 15.27.53](/attachments/e12a35eb-625c-4950-960e-61226eda4ad4)![Screen Shot 2023-07-17 at 15.28.11](/attachments/578bd742-8a8b-4324-82d4-b9dc47d7f511)![Screen Shot 2023-07-17 at 15.28.19](/attachments/f304bb80-c6cb-4af4-b16f-b19fa2099ba5) Co-authored-by: techknowlogick Co-authored-by: techknowlogick Reviewed-on: https://gitea.com/gitea/gitea-docusaurus/pulls/47 Co-authored-by: HesterG Co-committed-by: HesterG --- Makefile | 2 +- src/components/ActionCard/index.js | 22 +++++ src/components/ActionCard/styles.module.css | 53 +++++++++++ src/components/ActionFooter/footer.module.css | 19 ++++ src/components/ActionFooter/foss.svg | 4 + src/components/ActionFooter/index.js | 53 +++++++++++ src/components/ActionFooter/styles.module.css | 27 ++++++ src/components/ActionFooter/subscribeIcon.svg | 5 + src/components/Button/index.js | 66 +++++++++++++ src/components/Button/styles.module.css | 95 +++++++++++++++++++ src/components/Input/index.js | 21 ++++ src/components/Input/styles.module.css | 23 +++++ src/components/Section/index.js | 31 ++++++ src/components/Section/styles.module.css | 41 ++++++++ src/components/Subscribe/index.js | 39 ++++++++ src/components/Subscribe/style.module.css | 75 +++++++++++++++ src/components/SvgImage/index.js | 9 ++ src/css/custom.css | 54 ++++++++++- src/theme/ApiDoc/ApiDoc.jsx | 16 ++++ src/theme/ApiDoc/index.js | 2 + src/theme/DocPage/Layout/index.js | 36 +++++++ src/theme/DocPage/Layout/styles.module.css | 9 ++ 22 files changed, 699 insertions(+), 3 deletions(-) create mode 100644 src/components/ActionCard/index.js create mode 100644 src/components/ActionCard/styles.module.css create mode 100644 src/components/ActionFooter/footer.module.css create mode 100644 src/components/ActionFooter/foss.svg create mode 100644 src/components/ActionFooter/index.js create mode 100644 src/components/ActionFooter/styles.module.css create mode 100644 src/components/ActionFooter/subscribeIcon.svg create mode 100644 src/components/Button/index.js create mode 100644 src/components/Button/styles.module.css create mode 100644 src/components/Input/index.js create mode 100644 src/components/Input/styles.module.css create mode 100644 src/components/Section/index.js create mode 100644 src/components/Section/styles.module.css create mode 100644 src/components/Subscribe/index.js create mode 100644 src/components/Subscribe/style.module.css create mode 100644 src/components/SvgImage/index.js create mode 100644 src/theme/ApiDoc/ApiDoc.jsx create mode 100644 src/theme/ApiDoc/index.js create mode 100644 src/theme/DocPage/Layout/index.js create mode 100644 src/theme/DocPage/Layout/styles.module.css diff --git a/Makefile b/Makefile index 7d67d252..6d57ac40 100644 --- a/Makefile +++ b/Makefile @@ -1,4 +1,4 @@ -export NODE_OPTIONS := "--max-old-space-size=4096" +export NODE_OPTIONS := "--max-old-space-size=8192" .PHONY: all all: build diff --git a/src/components/ActionCard/index.js b/src/components/ActionCard/index.js new file mode 100644 index 00000000..dc528bfb --- /dev/null +++ b/src/components/ActionCard/index.js @@ -0,0 +1,22 @@ +import clsx from "clsx"; +import React from "react"; +import style from "./styles.module.css"; + +// skin?: "default" | "primary" +export const ActionCard = ({ skin = "default", icon, title, description, svgBackgroundColor, children, className }) => { + const styles = { background: svgBackgroundColor}; + return ( +
+
{icon}
+

{title}

+

{description}

+
{children}
+
+ ) +} + +export default ActionCard diff --git a/src/components/ActionCard/styles.module.css b/src/components/ActionCard/styles.module.css new file mode 100644 index 00000000..8bc5b3de --- /dev/null +++ b/src/components/ActionCard/styles.module.css @@ -0,0 +1,53 @@ +.root { + padding: 2rem; + border-radius: 16px; + background: var(--theme-attention-card-bg-color); +} + +.title { + margin-top: 1rem; + margin-bottom: 1rem; + font-size: var(--font-size-big-1); + font-weight: var(--ifm-font-weight-bold); +} + +.description { + font-size: var(--font-size-large); +} + +@media screen and (min-width: 880px) { + .root { + padding: 2rem; + } + + .title { + font-size: 1.2rem; + } +} + +.content { + display: flex; + flex: 1; +} + +.skinPrimary { + background: var(--ifm-color-primary-lighter); +} + +[data-theme='dark'] .skinPrimary { + background: var(--ifm-color-primary-darker); +} + +.skinPrimary .title, +.skinPrimary .description { + color: var(--theme-attention-card-text-color); +} + +.icon { + display: flex; + align-items: center; + justify-content: center; + height: 76px; + width: 76px; + border-radius: 50%; +} diff --git a/src/components/ActionFooter/footer.module.css b/src/components/ActionFooter/footer.module.css new file mode 100644 index 00000000..34472619 --- /dev/null +++ b/src/components/ActionFooter/footer.module.css @@ -0,0 +1,19 @@ +.cards { + display: grid; + gap: 1.5rem; +} + +.card__link { + text-transform: uppercase; + font-size: var(--font-size-normal); +} + +.card__link:not(:last-child) { + margin-right: 1.5rem; +} + +@media screen and (min-width: 768px) { + .cards { + grid-template-columns: 1fr 1fr; + } +} diff --git a/src/components/ActionFooter/foss.svg b/src/components/ActionFooter/foss.svg new file mode 100644 index 00000000..c1d6e82b --- /dev/null +++ b/src/components/ActionFooter/foss.svg @@ -0,0 +1,4 @@ + + + + diff --git a/src/components/ActionFooter/index.js b/src/components/ActionFooter/index.js new file mode 100644 index 00000000..a9b60614 --- /dev/null +++ b/src/components/ActionFooter/index.js @@ -0,0 +1,53 @@ +import footerCss from "./footer.module.css"; +import ActionCard from "../ActionCard"; +import FossIcon from "./foss.svg"; +import SubscribeIcon from "./subscribeIcon.svg"; +import Subscribe from "../Subscribe"; +import React from "react"; +import SvgImage from "../SvgImage"; + +export const ActionFooter = () => ( +
+ } + title="An icon showing wave propagation" + /> + } + svgBackgroundColor="#ffffff" + title="Join our community" + description="Gitea is open source. Star our GitHub repo, and join our community on Discord!" + > + + Go to GitHub  > + + + Join Discord  > + + + + } + title="An icon showing a paper plane" + /> + } + skin="primary" + > + + +
+) diff --git a/src/components/ActionFooter/styles.module.css b/src/components/ActionFooter/styles.module.css new file mode 100644 index 00000000..37364172 --- /dev/null +++ b/src/components/ActionFooter/styles.module.css @@ -0,0 +1,27 @@ +.loader { + position: absolute; + width: 20px; + height: 20px; +} + +.loader:after { + content: " "; + display: block; + width: 14px; + height: 14px; + margin: 0; + border-radius: 50%; + border: 3px solid transparent; + border-color: var(--ifm-color-white) transparent var(--ifm-color-white) + transparent; + animation: loader 1.2s linear infinite; +} + +@keyframes loader { + 0% { + transform: rotate(0deg); + } + 100% { + transform: rotate(360deg); + } +} diff --git a/src/components/ActionFooter/subscribeIcon.svg b/src/components/ActionFooter/subscribeIcon.svg new file mode 100644 index 00000000..4024e56b --- /dev/null +++ b/src/components/ActionFooter/subscribeIcon.svg @@ -0,0 +1,5 @@ + + + + + diff --git a/src/components/Button/index.js b/src/components/Button/index.js new file mode 100644 index 00000000..94bdc4c1 --- /dev/null +++ b/src/components/Button/index.js @@ -0,0 +1,66 @@ +import clsx from "clsx"; +import React from "react"; + +import styles from "./styles.module.css"; + +const Button = (props) => { + const { icon, variant, size, uppercase, className, to, href, children } = props; + const classes = clsx(className, styles.button, { + [styles["button--icon"]]: icon != null, + [styles["button--primary"]]: variant === "primary", + [styles["button--secondary"]]: variant === "secondary", + [styles["button--small"]]: size === "small", + [styles["button--tertiary"]]: variant === "tertiary", + [styles["button--plain"]]: variant === "plain", + [styles["button--uppercase"]]: uppercase === "true", + [styles["button--xsmall"]]: size === "xsmall", + [styles["button--xxsmall"]]: size === "xxsmall", + }) + if (href != null) { + const { disabled, onClick, newtab} = props; + return ( + + {icon} + {children} + + ) + } + + if (to != null) { + return ( + + {icon} + {children} + + ) + } + + return ( + + ) +} + +Button.defaultProps = { + newtab: "true", + size: "normal", + uppercase: "true", + variant: "primary", +} + +export default Button diff --git a/src/components/Button/styles.module.css b/src/components/Button/styles.module.css new file mode 100644 index 00000000..c197b202 --- /dev/null +++ b/src/components/Button/styles.module.css @@ -0,0 +1,95 @@ +.button { + display: inline-flex; + align-items: center; + justify-content: center; + height: 55px; + padding: 0 2rem; + border: none; + border-radius: calc(var(--ifm-global-border-radius) / 2); + font-weight: var(--ifm-font-weight-bold); + font-size: var(--font-size-normal); + transition: background-color 100ms cubic-bezier(0.17, 0.67, 0.83, 0.67); +} + +.button:hover { + text-decoration: none; + cursor: pointer; +} + +.button--plain { + height: auto; + padding: 0; + font-weight: unset; + font-size: unset; +} + +.button--primary { + background-color: var(--theme-button-primary-background-color); + color: var(--theme-button-primary-text-color); } + +.button--primary:hover { + background-color: var(--theme-button-primary-hover-background-color); + color: var(--theme-button-primary-text-color); +} + +.button--icon img, .button--icon svg { + margin-right: 0.5rem; +} + +.button--secondary { + background-color: var(--theme-button-secondary-background-color); + color: var(--theme-button-secondary-text-color); +} + +.button--secondary:hover { + background-color: var(--theme-button-secondary-hover-background-color); + color: var(--theme-button-secondary-text-color); +} + +.button--tertiary { + background-color: var(--theme-button-tertiary-background-color); + color: var(--theme-button-tertiary-text-color); +} + +.button--tertiary:hover { + color: var(--theme-button-tertiary-text-color); + background-color: var(--theme-button-tertiary-hover-background-color); +} + +.button--small { + height: 3.5rem; +} + +.button--xsmall { + height: 2.6rem; + padding: 0 1rem; +} + +.button--xxsmall { + height: 2rem; + font-weight: normal; + font-size: 0.9rem; +} + +.button--uppercase { + text-transform: uppercase; +} + +@media (max-width: 996px) { + .button { + padding: 0 1.75rem; + } + + .button--xsmall { + padding: 0 1rem; + } + + .button--xxsmall { + padding: 0 0.9rem; + } + + + .button--plain { + padding: 0; + } +} diff --git a/src/components/Input/index.js b/src/components/Input/index.js new file mode 100644 index 00000000..804c7aeb --- /dev/null +++ b/src/components/Input/index.js @@ -0,0 +1,21 @@ +import clsx from "clsx"; +import React from "react"; + +import styles from "./styles.module.css"; + +const Input = (props) => { + const classes = clsx(props.className, styles.input) + + return ( + + ) +} + +Input.defaultProps = { + type: "text", +} + +export default Input diff --git a/src/components/Input/styles.module.css b/src/components/Input/styles.module.css new file mode 100644 index 00000000..f2546def --- /dev/null +++ b/src/components/Input/styles.module.css @@ -0,0 +1,23 @@ +.input { + display: flex; + height: 55px; + padding: 0 2rem; + align-items: center; + border-radius: calc(var(--ifm-global-border-radius) / 2); + border: none; + background: var(--palette-rock); + font-size: var(--font-size-normal); + color: var(--ifm-color-white); + border: 2px solid transparent; +} + +.input:focus { + outline: none; + border-color: var(--ifm-color-white); +} + +.input:placeholder { + color: var(--palette-pale-blue); + font-size: var(--font-size-normal); + font-weight: var(--ifm-font-weight-bold); +} diff --git a/src/components/Section/index.js b/src/components/Section/index.js new file mode 100644 index 00000000..9f5162e7 --- /dev/null +++ b/src/components/Section/index.js @@ -0,0 +1,31 @@ +import React from "react"; +import style from "./styles.module.css"; +import clsx from "clsx"; + +export const Section = ({ + fullWidth, + children, + odd, + accent, + row, + noGap, + center, + className = "", +}) => ( +
+ {children} +
+) diff --git a/src/components/Section/styles.module.css b/src/components/Section/styles.module.css new file mode 100644 index 00000000..63aedde3 --- /dev/null +++ b/src/components/Section/styles.module.css @@ -0,0 +1,41 @@ +.root { + display: flex; + flex-direction: column; + max-width: var(--ifm-container-width); + width: 100%; + padding: 2rem 1rem; + margin: 0 auto; +} + +@media screen and (min-width: 900px) { + .root { + padding: 4.5rem 2rem; + } +} + +.row { + flex-direction: row; +} + +.odd { + background-color: var(--theme-section-odd-bg-color); +} + +.accent { + --ifm-link-hover-color: var(--palette-pink); + --ifm-link-color: var(--palette-pink); + padding-top: 7rem; + padding-bottom: 7.5rem; +} + +.fullWidth { + max-width: 100%; +} + +.noGap { + padding: 0; +} + +.center { + align-items: center; +} diff --git a/src/components/Subscribe/index.js b/src/components/Subscribe/index.js new file mode 100644 index 00000000..c27023b7 --- /dev/null +++ b/src/components/Subscribe/index.js @@ -0,0 +1,39 @@ +import React, { useState } from "react" +import Input from "../Input" +import Button from "../Button" +import style from "./style.module.css" +import clsx from "clsx" + +const Spinner = () => + +const Subscribe = ({placeholder, submitButtonText, className, classNameInputs}) => { + const [loading, setLoading] = useState(false) + + return ( +
{setLoading(true)}}> +
+ + + + + +
+
+ ) +} + +export default Subscribe diff --git a/src/components/Subscribe/style.module.css b/src/components/Subscribe/style.module.css new file mode 100644 index 00000000..ee512904 --- /dev/null +++ b/src/components/Subscribe/style.module.css @@ -0,0 +1,75 @@ +.root { + width: 100%; +} + +.inputs { + display: grid; + gap: 1rem; +} + +:global(html[data-theme="light"]) .subscribeSubmit { + background: #dde0e9; +} + +:global(html[data-theme="light"]) .subscribeSubmit:hover { + opacity: 0.8; +} + +@media screen and (min-width: 600px) { + .inputs { + grid-template-columns: 4fr 2fr; + } +} + +.input { + color: var(--theme-input-text-color); + padding: 1rem; + font-size: var(--font-size-small); + width: 100%; + background-color: var(--theme-input-bg-color); +} + +.checkbox { + display: none !important; +} + +.input::placeholder { + color: var(--theme-input-text-color); +} + +.submit { + white-space: nowrap; +} + +.loader { + position: absolute; + width: 20px; + height: 20px; +} + +.loader:after { + content: " "; + display: block; + width: 14px; + height: 14px; + margin: 0; + border-radius: 50%; + border: 3px solid transparent; + border-color: var(--ifm-color-white) transparent var(--ifm-color-white) + transparent; + animation: loader 1.2s linear infinite; +} + +.success { + font-size: var(--font-size-large); + font-weight: var(--ifm-font-weight-bold); +} + +@keyframes loader { + 0% { + transform: rotate(0deg); + } + 100% { + transform: rotate(360deg); + } +} diff --git a/src/components/SvgImage/index.js b/src/components/SvgImage/index.js new file mode 100644 index 00000000..81045898 --- /dev/null +++ b/src/components/SvgImage/index.js @@ -0,0 +1,9 @@ +import { cloneElement } from "react"; + +const SvgImage = ({ image, title = "" }) => + cloneElement(image, { + ...image.props, + title, + }) + +export default SvgImage diff --git a/src/css/custom.css b/src/css/custom.css index 039d7e3e..8c3b9694 100644 --- a/src/css/custom.css +++ b/src/css/custom.css @@ -6,6 +6,25 @@ /* You can override the default Infima variables here. */ :root { + --font-size-small: 15px; + --font-size-normal: 16px; + --font-size-large: 17px; + --font-size-big-1: 22px; + --font-size-big-2: 24px; + --font-size-big-3: 32px; + --font-size-big-4: 46px; + --font-size-big-5: 64px; + --palette-dark-10: rgba(0, 0, 0, 0.1); + --palette-dark-20: rgba(0, 0, 0, 0.2); + --palette-dark-30: rgba(0, 0, 0, 0.3); + --palette-dark-40: rgba(0, 0, 0, 0.4); + --palette-dark-60: rgba(0, 0, 0, 0.6); + --palette-dark-80: rgba(0, 0, 0, 0.8); + --palette-white-10: rgba(255, 255, 255, 0.1); + --palette-white-20: rgba(255, 255, 255, 0.2); + --palette-charade: #21222c; + --palette-rock: #262833; + --palette-pale-blue: #b1b5d3; --ifm-color-primary: #2e8555; --ifm-color-primary-dark: #29784c; --ifm-color-primary-darker: #277148; @@ -14,11 +33,29 @@ --ifm-color-primary-lighter: #359962; --ifm-color-primary-lightest: #3cad6e; --ifm-code-font-size: 95%; - --docusaurus-highlighted-code-line-bg: rgba(0, 0, 0, 0.1); + --ifm-global-border-radius: 8px; + --docusaurus-highlighted-code-line-bg: var(--palette-dark-10); + --theme-card-text-color: var(--palette-charade); + --theme-card-title-color: var(--palette-charade); + --theme-attention-card-bg-color: #f0f1f5; + --theme-attention-card-text-color: var(--ifm-color-white); + --theme-input-text-color: #555b88; + --theme-card-secondary-bg-color: #dde0e9; + --theme-button-primary-background-color: var(--ifm-color-primary); + --theme-button-primary-text-color: var(--ifm-color-white); + --theme-button-primary-hover-background-color: var(--ifm-color-primary-darker); + --theme-button-secondary-background-color: var(--palette-dark-10); + --theme-button-secondary-text-color: var(--palette-charade); + --theme-button-secondary-hover-background-color: var(--palette-dark-30); + --theme-button-tertiary-background-color: var(--palette-dark-30); + --theme-button-tertiary-text-color: var(--palette-dark-80); + --theme-button-tertiary-hover-background-color: var(--palette-dark-40); + --theme-input-bg-color: #f0f1f5; } /* For readability concerns, you should choose a lighter palette in dark mode. */ [data-theme='dark'] { + --palette-gray: #4b4e5d; --ifm-color-primary: #25c2a0; --ifm-color-primary-dark: #21af90; --ifm-color-primary-darker: #1fa588; @@ -26,7 +63,20 @@ --ifm-color-primary-light: #29d5b0; --ifm-color-primary-lighter: #32d8b4; --ifm-color-primary-lightest: #4fddbf; - --docusaurus-highlighted-code-line-bg: rgba(0, 0, 0, 0.3); + --docusaurus-highlighted-code-line-bg: var(--palette-dark-30); + --theme-attention-card-bg-color: var(--palette-gray); + --theme-input-bg-color: #44475a; + --theme-input-text-color: #b1b5d3; + --theme-card-secondary-bg-color: var(--palette-charade); + --theme-button-primary-background-color: var(--ifm-color-primary); + --theme-button-primary-text-color: var(--ifm-color-white); + --theme-button-primary-hover-background-color: var(--ifm-color-primary-darker); + --theme-button-secondary-background-color: var(--ifm-color-white); + --theme-button-secondary-text-color: var(--palette-charade); + --theme-button-secondary-hover-background-color: #d9d9d9; + --theme-button-tertiary-background-color: var(--palette-white-10); + --theme-button-tertiary-text-color: var(--ifm-color-white); + --theme-button-tertiary-hover-background-color: var(--palette-white-20); } [data-theme='dark'] [class*='announcementBar'] { diff --git a/src/theme/ApiDoc/ApiDoc.jsx b/src/theme/ApiDoc/ApiDoc.jsx new file mode 100644 index 00000000..3b0121a4 --- /dev/null +++ b/src/theme/ApiDoc/ApiDoc.jsx @@ -0,0 +1,16 @@ +import React from 'react'; +import Layout from '@theme/Layout'; +import Redoc from '@theme/Redoc'; +import { ActionFooter } from "@site/src/components/ActionFooter"; +import { Section } from "@site/src/components/Section"; +function ApiDoc({ layoutProps, specProps }) { + const defaultTitle = specProps.spec?.info?.title || 'API Docs'; + const defaultDescription = specProps.spec?.info?.description || 'Open API Reference Docs for the API'; + return ( + +
+ +
+
); +} +export default ApiDoc; diff --git a/src/theme/ApiDoc/index.js b/src/theme/ApiDoc/index.js new file mode 100644 index 00000000..b9d038b0 --- /dev/null +++ b/src/theme/ApiDoc/index.js @@ -0,0 +1,2 @@ +import ApiDoc from './ApiDoc'; +export default ApiDoc; diff --git a/src/theme/DocPage/Layout/index.js b/src/theme/DocPage/Layout/index.js new file mode 100644 index 00000000..8a02a1c5 --- /dev/null +++ b/src/theme/DocPage/Layout/index.js @@ -0,0 +1,36 @@ +// Ejected unsafe, need to check if this changes and maintain this component +// https://github.com/facebook/docusaurus/blob/docusaurus-v2/packages/docusaurus-theme-classic/src/theme/DocPage/Layout/index.tsx +import React, {useState} from 'react'; +import {useDocsSidebar} from '@docusaurus/theme-common/internal'; +import Layout from '@theme/Layout'; +import BackToTopButton from '@theme/BackToTopButton'; +import DocPageLayoutSidebar from '@theme/DocPage/Layout/Sidebar'; +import DocPageLayoutMain from '@theme/DocPage/Layout/Main'; +import styles from './styles.module.css'; +import { ActionFooter } from "@site/src/components/ActionFooter"; +import { Section } from "@site/src/components/Section"; + +export default function DocPageLayout({children}) { + const sidebar = useDocsSidebar(); + const [hiddenSidebarContainer, setHiddenSidebarContainer] = useState(false); + return ( + + +
+ {sidebar && ( + + )} + + {children} + +
+
+ +
+
+ ); +} diff --git a/src/theme/DocPage/Layout/styles.module.css b/src/theme/DocPage/Layout/styles.module.css new file mode 100644 index 00000000..74795779 --- /dev/null +++ b/src/theme/DocPage/Layout/styles.module.css @@ -0,0 +1,9 @@ +.docPage { + display: flex; + width: 100%; +} + +.docsWrapper { + display: flex; + flex: 1 0 auto; +}