mirror of https://gitea.com/gitea/blog.git
Add subscribe and community components, adjust blog width, update readme (#272)
- Updated readme - Used double quotes instead of single quotes - Increase blog content width Before ![Screen Shot 2023-07-14 at 13.45.45](/attachments/9c669c42-2efd-4ae5-bbf5-24f252c26fa0) After ![Screen Shot 2023-07-14 at 13.45.31](/attachments/6f72912c-2fd9-4a63-8839-583864faa474) - Added subscribe and community components to buttom of the blog post page. ![Screen Shot 2023-07-14 at 15.55.12](/attachments/3808fa5a-e951-487b-8ed2-dc693cfec9e2) ![Screen Shot 2023-07-14 at 15.55.30](/attachments/864ff357-a116-47ce-abf0-8278e24ede7d) Loading: ![Screen Shot 2023-07-14 at 15.57.00](/attachments/2f0ace67-d83e-4415-a778-8e7913fb6505) Post sent: ![Screen Shot 2023-07-14 at 13.48.44](/attachments/ceac4970-a914-49d5-ad42-febb3d259d89) Mobile: ![Screen Shot 2023-07-14 at 15.58.19](/attachments/7e01f575-7e4d-4d99-9888-7fb246ceb313) ![Screen Shot 2023-07-14 at 15.58.27](/attachments/879128d1-f115-41a7-8e8e-574f0b3de208) Reviewed-on: https://gitea.com/gitea/blog/pulls/272 Co-authored-by: HesterG <hestergong@gmail.com> Co-committed-by: HesterG <hestergong@gmail.com>
This commit is contained in:
parent
42fd823b6e
commit
c3d361092e
14
README.md
14
README.md
|
@ -13,13 +13,13 @@ If you want to host this page on your own you can take our docker image
|
|||
|
||||
## Install
|
||||
|
||||
This website uses the [Hugo](https://github.com/spf13/hugo) static site
|
||||
generator. If you are planning to contribute you'll want to download and install
|
||||
Hugo on your local machine.
|
||||
This website uses the [Docusaurus](https://docusaurus.io/) static site
|
||||
generator. If you are planning to contribute you'll want to install
|
||||
Docusaurus on your local machine.
|
||||
|
||||
The installation of Hugo is out of the scope of this document, so please take
|
||||
the [official install instructions](https://gohugo.io/overview/installing/) to
|
||||
get Hugo up and running.
|
||||
The installation of Docusaurus is out of the scope of this document, so please take
|
||||
the [official install instructions](https://docusaurus.io/docs/installation) to
|
||||
get Docusaurus up and running.
|
||||
|
||||
## Development
|
||||
|
||||
|
@ -27,7 +27,7 @@ To generate the website and serve it on [localhost:1313](http://localhost:1313)
|
|||
just execute this command and stop it with `Ctrl+C`:
|
||||
|
||||
```
|
||||
make server
|
||||
npm run start
|
||||
```
|
||||
|
||||
When you are done with your changes just create a pull request, after merging
|
||||
|
|
|
@ -4,12 +4,12 @@
|
|||
"private": true,
|
||||
"scripts": {
|
||||
"docusaurus": "docusaurus",
|
||||
"start": "docusaurus start",
|
||||
"start": "docusaurus start --port 1313",
|
||||
"build": "docusaurus build",
|
||||
"swizzle": "docusaurus swizzle",
|
||||
"deploy": "docusaurus deploy",
|
||||
"clear": "docusaurus clear",
|
||||
"serve": "docusaurus serve",
|
||||
"serve": "docusaurus serve --port 1313",
|
||||
"write-translations": "docusaurus write-translations",
|
||||
"write-heading-ids": "docusaurus write-heading-ids"
|
||||
},
|
||||
|
|
|
@ -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 (
|
||||
<div
|
||||
className={clsx(style.root, className, {
|
||||
[style.skinPrimary]: skin === "primary",
|
||||
})}
|
||||
>
|
||||
<div className={style.icon} style={styles}>{icon}</div>
|
||||
<h3 className={style.title}>{title}</h3>
|
||||
<p className={style.description}>{description}</p>
|
||||
<div className={style.content}>{children}</div>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
export default ActionCard
|
|
@ -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%;
|
||||
}
|
|
@ -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;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,4 @@
|
|||
<svg xmlns="http://www.w3.org/2000/svg" width="45" height="45" viewBox="0 0 576 512">
|
||||
<!--! Font Awesome Free 6.4.0 by @fontawesome - https://fontawesome.com License - https://fontawesome.com/license (Commercial License) Copyright 2023 Fonticons, Inc. -->
|
||||
<path d="M80.3 44C69.8 69.9 64 98.2 64 128s5.8 58.1 16.3 84c6.6 16.4-1.3 35-17.7 41.7s-35-1.3-41.7-17.7C7.4 202.6 0 166.1 0 128S7.4 53.4 20.9 20C27.6 3.6 46.2-4.3 62.6 2.3S86.9 27.6 80.3 44zM555.1 20C568.6 53.4 576 89.9 576 128s-7.4 74.6-20.9 108c-6.6 16.4-25.3 24.3-41.7 17.7S489.1 228.4 495.7 212c10.5-25.9 16.3-54.2 16.3-84s-5.8-58.1-16.3-84C489.1 27.6 497 9 513.4 2.3s35 1.3 41.7 17.7zM352 128c0 23.7-12.9 44.4-32 55.4V480c0 17.7-14.3 32-32 32s-32-14.3-32-32V183.4c-19.1-11.1-32-31.7-32-55.4c0-35.3 28.7-64 64-64s64 28.7 64 64zM170.6 76.8C163.8 92.4 160 109.7 160 128s3.8 35.6 10.6 51.2c7.1 16.2-.3 35.1-16.5 42.1s-35.1-.3-42.1-16.5c-10.3-23.6-16-49.6-16-76.8s5.7-53.2 16-76.8c7.1-16.2 25.9-23.6 42.1-16.5s23.6 25.9 16.5 42.1zM464 51.2c10.3 23.6 16 49.6 16 76.8s-5.7 53.2-16 76.8c-7.1 16.2-25.9 23.6-42.1 16.5s-23.6-25.9-16.5-42.1c6.8-15.6 10.6-32.9 10.6-51.2s-3.8-35.6-10.6-51.2c-7.1-16.2 .3-35.1 16.5-42.1s35.1 .3 42.1 16.5z"/>
|
||||
</svg>
|
After Width: | Height: | Size: 1.2 KiB |
|
@ -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 = () => (
|
||||
<div className={footerCss.cards}>
|
||||
<ActionCard
|
||||
icon={
|
||||
<SvgImage
|
||||
image={<FossIcon />}
|
||||
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!"
|
||||
>
|
||||
<a
|
||||
className={footerCss.card__link}
|
||||
href={'https://github.com/go-gitea/gitea'}
|
||||
rel="noopener noreferrer"
|
||||
target="_blank"
|
||||
>
|
||||
Go to GitHub >
|
||||
</a>
|
||||
<a className={footerCss.card__link} href={'https://discord.com/invite/gitea'}>
|
||||
Join Discord >
|
||||
</a>
|
||||
</ActionCard>
|
||||
|
||||
<ActionCard
|
||||
title="Subscribe to our newsletter"
|
||||
description="Stay up to date with all things Gitea"
|
||||
svgBackgroundColor="#1E1F27"
|
||||
icon={
|
||||
<SvgImage
|
||||
image={<SubscribeIcon />}
|
||||
title="An icon showing a paper plane"
|
||||
/>
|
||||
}
|
||||
skin="primary"
|
||||
>
|
||||
<Subscribe
|
||||
placeholder="Email address"
|
||||
submitButtonText = "Subscribe"
|
||||
/>
|
||||
</ActionCard>
|
||||
</div>
|
||||
)
|
|
@ -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);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,5 @@
|
|||
<svg xmlns="http://www.w3.org/2000/svg" width="45" height="45" viewBox="0 0 512 512">
|
||||
<!--! Font Awesome Free 6.4.0 by @fontawesome - https://fontawesome.com License - https://fontawesome.com/license (Commercial License) Copyright 2023 Fonticons, Inc. -->
|
||||
<style>svg{fill:#ffffff}</style>
|
||||
<path d="M16.1 260.2c-22.6 12.9-20.5 47.3 3.6 57.3L160 376V479.3c0 18.1 14.6 32.7 32.7 32.7c9.7 0 18.9-4.3 25.1-11.8l62-74.3 123.9 51.6c18.9 7.9 40.8-4.5 43.9-24.7l64-416c1.9-12.1-3.4-24.3-13.5-31.2s-23.3-7.5-34-1.4l-448 256zm52.1 25.5L409.7 90.6 190.1 336l1.2 1L68.2 285.7zM403.3 425.4L236.7 355.9 450.8 116.6 403.3 425.4z"/>
|
||||
</svg>
|
After Width: | Height: | Size: 623 B |
|
@ -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 (
|
||||
<a
|
||||
className={classes}
|
||||
{...(disabled ?? false ? {} : {
|
||||
href,
|
||||
onClick,
|
||||
})}
|
||||
{...(newtab === "true" ? {
|
||||
rel: "noopener noreferrer",
|
||||
target: "_blank",
|
||||
} : {})}
|
||||
>
|
||||
{icon}
|
||||
{children}
|
||||
</a>
|
||||
)
|
||||
}
|
||||
|
||||
if (to != null) {
|
||||
return (
|
||||
<a className={classes} href={to} onClick={onClick}>
|
||||
{icon}
|
||||
{children}
|
||||
</a>
|
||||
)
|
||||
}
|
||||
|
||||
return (
|
||||
<button
|
||||
{...props}
|
||||
className={classes}
|
||||
>
|
||||
{icon}
|
||||
{children}
|
||||
</button>
|
||||
)
|
||||
}
|
||||
|
||||
Button.defaultProps = {
|
||||
newtab: "true",
|
||||
size: "normal",
|
||||
uppercase: "true",
|
||||
variant: "primary",
|
||||
}
|
||||
|
||||
export default Button
|
|
@ -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;
|
||||
}
|
||||
}
|
|
@ -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
|
||||
{...props}
|
||||
className={classes}
|
||||
/>
|
||||
)
|
||||
}
|
||||
|
||||
Input.defaultProps = {
|
||||
type: "text",
|
||||
}
|
||||
|
||||
export default Input
|
|
@ -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);
|
||||
}
|
|
@ -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 = "",
|
||||
}) => (
|
||||
<div
|
||||
className={clsx(
|
||||
style.root,
|
||||
{
|
||||
[style.odd]: odd,
|
||||
[style.accent]: accent,
|
||||
[style.row]: row,
|
||||
[style.fullWidth]: fullWidth,
|
||||
[style.noGap]: noGap,
|
||||
[style.center]: center,
|
||||
},
|
||||
className,
|
||||
)}
|
||||
>
|
||||
{children}
|
||||
</div>
|
||||
)
|
|
@ -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;
|
||||
}
|
|
@ -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 = () => <span className={style.loader} />
|
||||
|
||||
const Subscribe = ({placeholder, submitButtonText, className, classNameInputs}) => {
|
||||
const [loading, setLoading] = useState(false)
|
||||
|
||||
return (
|
||||
<form method="post" action="https://list.gitea.com/subscription/form" className={clsx(style.root, className)} onSubmit={() => {setLoading(true)}}>
|
||||
<div className={clsx(style.inputs, classNameInputs)}>
|
||||
<Input type="hidden" name="nonce" />
|
||||
<Input className={style.checkbox} id="2aae7" type="checkbox" name="l" value="2aae7a49-b6b9-4aa3-b35a-32c9aeace57b" checked readOnly />
|
||||
<Input
|
||||
className={style.input}
|
||||
name="email"
|
||||
type="email"
|
||||
title="Email address should be valid"
|
||||
placeholder={placeholder}
|
||||
required
|
||||
autoComplete="off"
|
||||
/>
|
||||
|
||||
<Button
|
||||
variant={"tertiary"}
|
||||
type="submit"
|
||||
className={style.subscribeSubmit}
|
||||
>
|
||||
{loading ? <Spinner /> : submitButtonText}
|
||||
</Button>
|
||||
</div>
|
||||
</form>
|
||||
)
|
||||
}
|
||||
|
||||
export default Subscribe
|
|
@ -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;
|
||||
}
|
||||
|
||||
.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);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,9 @@
|
|||
import { cloneElement } from "react";
|
||||
|
||||
const SvgImage = ({ image, title = "" }) =>
|
||||
cloneElement(image, {
|
||||
...image.props,
|
||||
title,
|
||||
})
|
||||
|
||||
export default SvgImage
|
|
@ -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,16 +33,32 @@
|
|||
--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-bg-color: #f0f1f5;
|
||||
--theme-card-bg-color-hover: rgb(225, 227, 235);
|
||||
--theme-card-border-color: #b7b9c3;
|
||||
--theme-card-text-color: #21222c;
|
||||
--theme-card-title-color: #21222c;
|
||||
--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;
|
||||
|
@ -31,13 +66,26 @@
|
|||
--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-card-text-color: var(--ifm-color-white);
|
||||
--theme-card-title-color: var(--ifm-color-white);
|
||||
--theme-card-bg-color: #262833;
|
||||
--theme-card-bg-color: var(--palette-rock);
|
||||
--theme-card-bg-color-hover: rgb(47, 49, 63);
|
||||
--theme-card-border-color: #51535f;
|
||||
--theme-card-border-radius: 8px;
|
||||
--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);
|
||||
}
|
||||
|
||||
.internal-href [class*='iconExternalLink'] {
|
||||
|
|
|
@ -0,0 +1,39 @@
|
|||
// Ejected unsafe, need to check if this changes and maintain this component
|
||||
// https://github.com/facebook/docusaurus/blob/main/packages/docusaurus-theme-classic/src/theme/BlogLayout/index.tsx
|
||||
import React from "react";
|
||||
import clsx from "clsx";
|
||||
import Layout from "@theme/Layout";
|
||||
import BlogSidebar from "@theme/BlogSidebar";
|
||||
import { ActionFooter } from "@site/src/components/ActionFooter";
|
||||
import { Section } from "@site/src/components/Section";
|
||||
|
||||
// customized:
|
||||
// - Use "col--9" for `main` if there is no toc
|
||||
// - Addded subscribe and community card to the bottom
|
||||
export default function BlogLayout(props) {
|
||||
const {sidebar, toc, children, ...layoutProps} = props;
|
||||
const hasSidebar = sidebar && sidebar.items.length > 0;
|
||||
return (
|
||||
<Layout {...layoutProps}>
|
||||
<div className="container margin-vert--lg">
|
||||
<div className="row">
|
||||
<BlogSidebar sidebar={sidebar} />
|
||||
<main
|
||||
className={clsx("col", {
|
||||
"col--7": hasSidebar,
|
||||
"col--9 col--offset-1": !hasSidebar,
|
||||
"col--9": !toc,
|
||||
})}
|
||||
itemScope
|
||||
itemType="http://schema.org/Blog">
|
||||
{children}
|
||||
</main>
|
||||
{toc && <div className="col col--2">{toc}</div>}
|
||||
</div>
|
||||
<Section>
|
||||
<ActionFooter />
|
||||
</Section>
|
||||
</div>
|
||||
</Layout>
|
||||
);
|
||||
}
|
|
@ -1,7 +1,7 @@
|
|||
import clsx from "clsx"
|
||||
import React from "react"
|
||||
import styles from "./styles.module.css"
|
||||
import Link from "@docusaurus/Link"
|
||||
import clsx from "clsx";
|
||||
import React from "react";
|
||||
import styles from "./styles.module.css";
|
||||
import Link from "@docusaurus/Link";
|
||||
|
||||
// type Skin = "primary" | "secondary"
|
||||
// type Size = "small" | "medium" | "large"
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
import React from 'react';
|
||||
import { Chip } from '../Chip';
|
||||
import styles from './styles.module.css';
|
||||
import { ensureTrailingSlash } from '@site/src/utils/ensureTrailingSlash.js';
|
||||
import React from "react";
|
||||
import { Chip } from "../Chip";
|
||||
import styles from "./styles.module.css";
|
||||
import { ensureTrailingSlash } from "@site/src/utils/ensureTrailingSlash.js";
|
||||
|
||||
export const Chips = ({ items, activeChipLabel }) => (
|
||||
<div className={styles.root}>
|
||||
|
|
|
@ -1,23 +1,23 @@
|
|||
import React from 'react';
|
||||
import styles from './styles.module.css';
|
||||
import Link from '@docusaurus/Link';
|
||||
import { Chip } from '../Chip';
|
||||
import { ensureTrailingSlash } from '@site/src/utils/ensureTrailingSlash.js';
|
||||
import React from "react";
|
||||
import styles from "./styles.module.css";
|
||||
import Link from "@docusaurus/Link";
|
||||
import { Chip } from "../Chip";
|
||||
import { ensureTrailingSlash } from "@site/src/utils/ensureTrailingSlash.js";
|
||||
|
||||
export const ListItem = ({ content, belowFold }) => {
|
||||
const {metadata, frontMatter} = content;
|
||||
const {tags, permalink, authors, title, formattedDate} = metadata;
|
||||
const tag = tags[0] ?? {};
|
||||
const imageUrl = frontMatter.coverImage ?? '/img/blog_placeholder.png';
|
||||
const imageUrl = frontMatter.coverImage ?? "/img/blog_placeholder.png";
|
||||
const postUrl = ensureTrailingSlash(permalink);
|
||||
return (
|
||||
<div className={styles.root}>
|
||||
<div className={styles.imageBox}>
|
||||
<Link to={postUrl} className={styles.image}>
|
||||
<img
|
||||
loading={belowFold ? 'lazy' : 'eager'}
|
||||
loading={belowFold ? "lazy" : "eager"}
|
||||
src={imageUrl}
|
||||
alt={`Banner for blog post with title '${title}'`}
|
||||
alt={`Banner for blog post with title "${title}"`}
|
||||
/>
|
||||
</Link>
|
||||
</div>
|
||||
|
@ -27,8 +27,8 @@ export const ListItem = ({ content, belowFold }) => {
|
|||
<Chip
|
||||
label={tag.label}
|
||||
permalink={tag.permalink}
|
||||
skin='secondary'
|
||||
size='small'
|
||||
skin="secondary"
|
||||
size="small"
|
||||
/>
|
||||
</div>
|
||||
|
||||
|
|
|
@ -1,23 +1,26 @@
|
|||
// Ejected unsafe, need to check if this changes and maintain this component
|
||||
// https://github.com/facebook/docusaurus/blob/main/packages/docusaurus-theme-classic/src/theme/BlogListPage/index.tsx
|
||||
import React from 'react';
|
||||
import clsx from 'clsx';
|
||||
import Layout from '@theme/Layout';
|
||||
import useDocusaurusContext from '@docusaurus/useDocusaurusContext';
|
||||
import React from "react";
|
||||
import clsx from "clsx";
|
||||
import Layout from "@theme/Layout";
|
||||
import useDocusaurusContext from "@docusaurus/useDocusaurusContext";
|
||||
import {
|
||||
PageMetadata,
|
||||
HtmlClassNameProvider,
|
||||
ThemeClassNames,
|
||||
} from '@docusaurus/theme-common';
|
||||
// import BlogLayout from '@theme/BlogLayout';
|
||||
import BlogListPaginator from '@theme/BlogListPaginator';
|
||||
import SearchMetadata from '@theme/SearchMetadata';
|
||||
// import BlogPostItems from '@theme/BlogPostItems';
|
||||
import { ListItem } from './ListItem';
|
||||
import { Chips } from './Chips';
|
||||
import styles from './styles.module.css';
|
||||
import useGlobalData from '@docusaurus/useGlobalData';
|
||||
} from "@docusaurus/theme-common";
|
||||
// import BlogLayout from "@theme/BlogLayout";
|
||||
import BlogListPaginator from "@theme/BlogListPaginator";
|
||||
import SearchMetadata from "@theme/SearchMetadata";
|
||||
// import BlogPostItems from "@theme/BlogPostItems";
|
||||
import { ListItem } from "./ListItem";
|
||||
import { Chips } from "./Chips";
|
||||
import styles from "./styles.module.css";
|
||||
import useGlobalData from "@docusaurus/useGlobalData";
|
||||
|
||||
// customized:
|
||||
// - Layout
|
||||
// - Tags list page
|
||||
function BlogListPageMetadata(props) {
|
||||
const isTagsPage = props.tag !== undefined;
|
||||
const metadata = isTagsPage ? props.listMetadata: props.metadata;
|
||||
|
@ -25,12 +28,12 @@ function BlogListPageMetadata(props) {
|
|||
siteConfig: {title: siteTitle},
|
||||
} = useDocusaurusContext();
|
||||
const {blogDescription, blogTitle, permalink} = metadata;
|
||||
const isBlogOnlyMode = permalink === '/';
|
||||
const isBlogOnlyMode = permalink === "/";
|
||||
const title = isBlogOnlyMode ? siteTitle : blogTitle;
|
||||
return (
|
||||
<>
|
||||
<PageMetadata title={title} description={blogDescription} />
|
||||
<SearchMetadata tag='blog_posts_list' />
|
||||
<SearchMetadata tag="blog_posts_list" />
|
||||
</>
|
||||
);
|
||||
}
|
||||
|
@ -41,7 +44,7 @@ function BlogListPageContent(props) {
|
|||
// No official api to get all tags right now: https://github.com/facebook/docusaurus/discussions/5856
|
||||
// So used customized blog plugin which extends original blog plugin
|
||||
const globalData = useGlobalData();
|
||||
const myPluginData = globalData['docusaurus-plugin-content-blog']['default'];
|
||||
const myPluginData = globalData["docusaurus-plugin-content-blog"]["default"];
|
||||
const tags = [];
|
||||
for (const {items, label, permalink} of Object.values(myPluginData.tags)) {
|
||||
tags.push({label, permalink});
|
||||
|
@ -56,7 +59,7 @@ function BlogListPageContent(props) {
|
|||
// <BlogPostItems items={items} />
|
||||
// <BlogListPaginator metadata={metadata} />
|
||||
// </BlogLayout>
|
||||
<Layout title='Blog'>
|
||||
<Layout title="Blog">
|
||||
<main className={styles.root}>
|
||||
<h2 className={styles.title}>Filter by Tag</h2>
|
||||
<div className={styles.categories}>
|
||||
|
@ -65,8 +68,8 @@ function BlogListPageContent(props) {
|
|||
items={tags}
|
||||
/>
|
||||
</div>
|
||||
<a className={styles.link} href='/'>Show all posts</a>
|
||||
<h2 className={styles.title}>{isTagsPage? `${tagPageCount !== -1 ? `${tagPageCount} posts`: 'Posts'} tagged with "${props.tag.label}"`: "Blog Posts"}</h2>
|
||||
<a className={styles.link} href="/">Show all posts</a>
|
||||
<h2 className={styles.title}>{isTagsPage? `${tagPageCount !== -1 ? `${tagPageCount} posts`: "Posts"} tagged with "${props.tag.label}"`: "Blog Posts"}</h2>
|
||||
<div className={styles.posts}>
|
||||
{items.map(({ content }, i) => (
|
||||
<ListItem
|
||||
|
|
|
@ -1,19 +1,19 @@
|
|||
// Ejected unsafe, need to check if this changes and maintain this component
|
||||
// https://github.com/facebook/docusaurus/blob/main/packages/docusaurus-theme-classic/src/theme/BlogPostPage/index.tsx
|
||||
import React from 'react';
|
||||
import clsx from 'clsx';
|
||||
import {HtmlClassNameProvider, ThemeClassNames} from '@docusaurus/theme-common';
|
||||
import {BlogPostProvider, useBlogPost} from '@docusaurus/theme-common/internal';
|
||||
import BlogLayout from '@theme/BlogLayout';
|
||||
import BlogPostItem from '@theme/BlogPostItem';
|
||||
import BlogPostPaginator from '@theme/BlogPostPaginator';
|
||||
import BlogPostPageMetadata from '@theme/BlogPostPage/Metadata';
|
||||
import TOC from '@theme/TOC';
|
||||
import styles from './styles.module.css';
|
||||
import React from "react";
|
||||
import clsx from "clsx";
|
||||
import {HtmlClassNameProvider, ThemeClassNames} from "@docusaurus/theme-common";
|
||||
import {BlogPostProvider, useBlogPost} from "@docusaurus/theme-common/internal";
|
||||
import BlogLayout from "@theme/BlogLayout";
|
||||
import BlogPostItem from "@theme/BlogPostItem";
|
||||
import BlogPostPaginator from "@theme/BlogPostPaginator";
|
||||
import BlogPostPageMetadata from "@theme/BlogPostPage/Metadata";
|
||||
import TOC from "@theme/TOC";
|
||||
import styles from "./styles.module.css";
|
||||
|
||||
// customized:
|
||||
// Hide toc
|
||||
// Added Cover Image to the post
|
||||
// - Hide toc
|
||||
// - Added Cover Image to the post
|
||||
function BlogPostPageContent({sidebar, children}) {
|
||||
const {metadata, toc} = useBlogPost();
|
||||
const {nextItem, prevItem, frontMatter, title} = metadata;
|
||||
|
@ -25,11 +25,12 @@ function BlogPostPageContent({sidebar, children}) {
|
|||
return (
|
||||
<BlogLayout
|
||||
sidebar={sidebar}
|
||||
toc={undefined}
|
||||
>
|
||||
<BlogPostItem>
|
||||
{frontMatter.coverImage && <figure>
|
||||
<img
|
||||
alt={`Banner for blog post with title '${title}'`}
|
||||
alt={`Banner for blog post with title "${title}"`}
|
||||
className={clsx(styles.image, {
|
||||
[styles["image--title"]]: children != null,
|
||||
})}
|
||||
|
|
Loading…
Reference in New Issue