= ({
30 | children,
31 | hyphenate = false,
32 | language = 'en',
33 | indent = false,
34 | }) => {
35 | let childrenArray: ReactNodeArray
36 |
37 | if (!Array.isArray(children)) {
38 | childrenArray = [children]
39 | } else {
40 | childrenArray = children
41 | }
42 |
43 | if (hyphenate) {
44 | childrenArray = childrenArray.map(node => {
45 | if (typeof node === 'string') {
46 | switch (language) {
47 | case 'pl':
48 | return polishHyphenate(node)
49 | case 'en':
50 | default:
51 | return englishHyphenate(node)
52 | }
53 | }
54 |
55 | return node
56 | })
57 | }
58 |
59 | return (
60 |
61 | {childrenArray}
62 |
63 | )
64 | }
65 |
--------------------------------------------------------------------------------
/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "blog.iama.re",
3 | "version": "0.1.0",
4 | "private": true,
5 | "dependencies": {
6 | "@mdx-js/runtime": "^1.0.20",
7 | "@microlink/react": "^4.0.1",
8 | "@reach/router": "^1.2.1",
9 | "@types/classnames": "^2.2.8",
10 | "@types/jest": "24.0.14",
11 | "@types/node": "12.0.8",
12 | "@types/pouchdb-browser": "^6.1.3",
13 | "@types/pouchdb-find": "^6.3.4",
14 | "@types/ramda": "^0.26.9",
15 | "@types/reach__router": "^1.2.4",
16 | "@types/react": "^16.8.20",
17 | "@types/react-dom": "16.8.4",
18 | "@types/react-syntax-highlighter": "^10.2.1",
19 | "classnames": "^2.2.6",
20 | "date-fns": "^2.0.0-alpha.34",
21 | "emotion": "^10.0.9",
22 | "hyphen": "^1.1.1",
23 | "normalize.css": "^8.0.1",
24 | "pouchdb-browser": "^7.1.1",
25 | "pouchdb-find": "^7.1.1",
26 | "ramda": "^0.26.1",
27 | "react": "^16.8.6",
28 | "react-dom": "^16.8.6",
29 | "react-scripts": "3.0.1",
30 | "react-syntax-highlighter": "^10.3.0",
31 | "remark-custom-blocks": "^2.3.3",
32 | "remark-macro": "^1.0.7",
33 | "styled-components": "^4.3.2",
34 | "typescript": "3.5.2",
35 | "use-async-effect": "^2.0.1"
36 | },
37 | "scripts": {
38 | "start": "react-scripts start",
39 | "build": "react-scripts build",
40 | "test": "react-scripts test",
41 | "eject": "react-scripts eject"
42 | },
43 | "eslintConfig": {
44 | "extends": "react-app"
45 | },
46 | "browserslist": {
47 | "production": [
48 | ">0.2%",
49 | "not dead",
50 | "not op_mini all"
51 | ],
52 | "development": [
53 | "last 1 chrome version",
54 | "last 1 firefox version",
55 | "last 1 safari version"
56 | ]
57 | }
58 | }
59 |
--------------------------------------------------------------------------------
/src/contexts/Database.tsx:
--------------------------------------------------------------------------------
1 | import React, { createContext, ReactNode, FunctionComponent, useCallback } from 'react'
2 | import PouchDB from 'pouchdb-browser'
3 | import PouchDBFind from 'pouchdb-find'
4 | import prop from 'ramda/es/prop'
5 |
6 | import { DB_URL } from '../constants'
7 | import { PostModel } from '../models/Post'
8 |
9 | PouchDB.plugin(PouchDBFind)
10 |
11 | const db = new PouchDB(DB_URL, { skip_setup: true })
12 |
13 | export type Result = PouchDB.Core.ExistingDocument
14 |
15 | export type DBContext = {
16 | getDatabaseInfo: () => Promise
17 | getRecentPosts: (limit?: number, skip?: number) => Promise[]>
18 | getPostById: (id: string) => Promise>
19 | getAttachment: (id: string, filename: string) => Promise
20 | }
21 |
22 | export const DBContext = createContext({} as DBContext)
23 |
24 | export type DatabaseProviderProps = {
25 | children: ReactNode
26 | }
27 |
28 | export const DatabaseProvider: FunctionComponent = ({ children }) => {
29 | const getDatabaseInfo = useCallback(async () => {
30 | return db.info()
31 | }, [])
32 |
33 | const getRecentPosts = useCallback(async (limit = 10, skip = 0) => {
34 | const result = await db.query('posts/all', {
35 | descending: true,
36 | endkey: skip,
37 | limit: limit,
38 | })
39 |
40 | return result.rows.map(prop('value'))
41 | }, [])
42 |
43 | const getPostById = useCallback(async (id: string) => {
44 | return db.get(id, { attachments: true })
45 | }, [])
46 |
47 | const getAttachment = useCallback(async (id: string, filename: string) => {
48 | return db.getAttachment(id, filename)
49 | }, [])
50 |
51 | const contextValue: DBContext = {
52 | getDatabaseInfo,
53 | getRecentPosts,
54 | getPostById,
55 | getAttachment,
56 | }
57 |
58 | return {children}
59 | }
60 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | This project was bootstrapped with [Create React App](https://github.com/facebook/create-react-app).
2 |
3 | ## Available Scripts
4 |
5 | In the project directory, you can run:
6 |
7 | ### `npm start`
8 |
9 | Runs the app in the development mode.
10 | Open [http://localhost:3000](http://localhost:3000) to view it in the browser.
11 |
12 | The page will reload if you make edits.
13 | You will also see any lint errors in the console.
14 |
15 | ### `npm test`
16 |
17 | Launches the test runner in the interactive watch mode.
18 | See the section about [running tests](https://facebook.github.io/create-react-app/docs/running-tests) for more information.
19 |
20 | ### `npm run build`
21 |
22 | Builds the app for production to the `build` folder.
23 | It correctly bundles React in production mode and optimizes the build for the best performance.
24 |
25 | The build is minified and the filenames include the hashes.
26 | Your app is ready to be deployed!
27 |
28 | See the section about [deployment](https://facebook.github.io/create-react-app/docs/deployment) for more information.
29 |
30 | ### `npm run eject`
31 |
32 | **Note: this is a one-way operation. Once you `eject`, you can’t go back!**
33 |
34 | If you aren’t satisfied with the build tool and configuration choices, you can `eject` at any time. This command will remove the single build dependency from your project.
35 |
36 | Instead, it will copy all the configuration files and the transitive dependencies (Webpack, Babel, ESLint, etc) right into your project so you have full control over them. All of the commands except `eject` will still work, but they will point to the copied scripts so you can tweak them. At this point you’re on your own.
37 |
38 | You don’t have to ever use `eject`. The curated feature set is suitable for small and middle deployments, and you shouldn’t feel obligated to use this feature. However we understand that this tool wouldn’t be useful if you couldn’t customize it when you are ready for it.
39 |
40 | ## Learn More
41 |
42 | You can learn more in the [Create React App documentation](https://facebook.github.io/create-react-app/docs/getting-started).
43 |
44 | To learn React, check out the [React documentation](https://reactjs.org/).
45 |
--------------------------------------------------------------------------------
/src/components/Markdown/index.tsx:
--------------------------------------------------------------------------------
1 | import React, { FunctionComponent } from 'react'
2 | import MDX from '@mdx-js/runtime'
3 | import remarkCustomBlocks from 'remark-custom-blocks'
4 | import macro from 'remark-macro'
5 |
6 | import { Paragraph, Sidenote, Code, Link, Image, H1, H2, H3, H4, CodeTag } from '../index'
7 |
8 | const macroPlugin = macro()
9 |
10 | macroPlugin.addMacro(
11 | 'preview',
12 | props => {
13 | return {
14 | type: 'NoteNode',
15 | data: {
16 | hName: 'a',
17 | hProperties: { className: 'link-previews', href: props.src },
18 | hChildren: [{ type: 'text', value: props.src }],
19 | },
20 | }
21 | },
22 | true
23 | )
24 | const admonitionConfig: Record = {}
25 | const admonitionTypes = ['abstract', 'note', 'danger', 'warning', 'info', 'success', 'fail', 'question', 'example']
26 |
27 | admonitionTypes.forEach(type => {
28 | admonitionConfig[type] = {
29 | classes: `admonition-${type}`,
30 | title: 'optional',
31 | }
32 | admonitionConfig[`${type}-spoiler`] = {
33 | classes: `admonition-${type}`,
34 | title: 'required',
35 | details: true,
36 | }
37 | })
38 |
39 | admonitionConfig['spoiler'] = {
40 | classes: 'admonition-spoiler',
41 | title: 'required',
42 | details: true,
43 | }
44 |
45 | export type MarkdownProps = {
46 | scope?: object
47 | text: string
48 | }
49 |
50 | export const Markdown: FunctionComponent = ({ text, scope = {} }) => {
51 | return (
52 |
70 | {text}
71 |
72 | )
73 | }
74 |
--------------------------------------------------------------------------------
/src/views/Home.tsx:
--------------------------------------------------------------------------------
1 | import React, { FunctionComponent, useContext, useState } from 'react'
2 | import { RouteComponentProps } from '@reach/router'
3 | import { useAsyncEffect } from 'use-async-effect'
4 | import distanceToNow from 'date-fns/formatDistanceToNow'
5 |
6 | import { DBContext, Result } from '../contexts/Database'
7 | import { PostModel, postCreatedAt } from '../models/Post'
8 | import { Spinner, Paragraph, Link, Separator } from '../components'
9 |
10 | export type HomeProps = RouteComponentProps
11 |
12 | export const Home: FunctionComponent = () => {
13 | const { getRecentPosts } = useContext(DBContext)
14 | const [posts, setPosts] = useState[]>([])
15 | const [isLoading, setLoading] = useState(true)
16 |
17 | useAsyncEffect(
18 | async () => {
19 | const posts = await getRecentPosts()
20 |
21 | setPosts(posts)
22 | setLoading(false)
23 | },
24 | undefined,
25 | []
26 | )
27 |
28 | if (isLoading) {
29 | return
30 | }
31 |
32 | if (!isLoading && posts.length === 0) {
33 | return <>There are no posts to display.>
34 | }
35 |
36 | return (
37 | <>
38 |
39 | Hi there! I'm Arè. This is a collection of my articles and thoughts. This blog has been written
40 | as a serverless CouchDB-powered app. Please excuse the size of the bundle, this is mostly a playground
41 | for me. Code powering this blog is available on{' '}
42 | Github.
43 |
44 |
45 | {posts.map(post => {
46 | const createdAt = postCreatedAt(post)
47 | return (
48 |
49 |
50 | {post.title}
51 | {' '}
52 |
53 | by @{post.author} —
54 | {distanceToNow(createdAt)} ago
55 |
56 |
57 | )
58 | })}
59 | >
60 | )
61 | }
62 |
--------------------------------------------------------------------------------
/src/views/Post.tsx:
--------------------------------------------------------------------------------
1 | import React, { FunctionComponent, useState, useContext } from 'react'
2 | import { RouteComponentProps, Redirect } from '@reach/router'
3 | import distanceToNow from 'date-fns/formatDistanceToNow'
4 | import { useAsyncEffect } from 'use-async-effect'
5 |
6 | import { PostModel, postCreatedAt, postUpdatedAt } from '../models/Post'
7 |
8 | import { Title, Nav, Link, Spinner } from '../components'
9 | import { Markdown } from '../components/Markdown'
10 | import { DBContext } from '../contexts/Database'
11 |
12 | export type PostProps = RouteComponentProps<{
13 | id: string
14 | }>
15 |
16 | export const Post: FunctionComponent = ({ id }) => {
17 | const { getPostById } = useContext(DBContext)
18 | const [post, setPost] = useState()
19 | const [error, setError] = useState(null)
20 |
21 | useAsyncEffect(
22 | async () => {
23 | if (!id) {
24 | return setError('404')
25 | }
26 |
27 | try {
28 | const post = await getPostById(id)
29 |
30 | if (!post) {
31 | return setError('404')
32 | }
33 |
34 | setPost(post)
35 | } catch (e) {
36 | if (e.error === 'not_found') {
37 | return setError('404')
38 | }
39 |
40 | return setError('404')
41 | }
42 | },
43 | undefined,
44 | [id]
45 | )
46 |
47 | if (error === '404') {
48 | return
49 | }
50 |
51 | if (!post) {
52 | return
53 | }
54 |
55 | const createdAt = postCreatedAt(post)
56 | const updatedAt = postUpdatedAt(post)
57 |
58 | return (
59 | <>
60 |
71 | {post.title}
72 |
73 | >
74 | )
75 | }
76 |
--------------------------------------------------------------------------------
/src/types/index.d.ts:
--------------------------------------------------------------------------------
1 | declare module 'hyphen' {
2 | export type HyphenationPatterns = {
3 | patterns: string[]
4 | exceptions: string[]
5 | }
6 |
7 | export default function createHyphenator(patterns: HyphenationPatterns): (text: string) => string
8 | }
9 |
10 | declare module 'hyphen/patterns/en-us' {
11 | import { HyphenationPatterns } from 'hyphen'
12 |
13 | var englishHyphenationPatterns: HyphenationPatterns
14 |
15 | export default englishHyphenationPatterns
16 | }
17 |
18 | declare module 'hyphen/patterns/pl' {
19 | import { HyphenationPatterns } from 'hyphen'
20 |
21 | var polishHyphenationPatterns: HyphenationPatterns
22 |
23 | export default polishHyphenationPatterns
24 | }
25 |
26 | declare module 'react-syntax-highlighter/dist/languages/prism/jsx' {
27 | var language: string
28 | export default language
29 | }
30 |
31 | declare module 'react-syntax-highlighter/dist/languages/prism/typescript' {
32 | var language: string
33 | export default language
34 | }
35 |
36 | declare module 'react-syntax-highlighter/dist/languages/prism/yaml' {
37 | var language: string
38 | export default language
39 | }
40 |
41 | declare module 'react-syntax-highlighter/dist/languages/prism/twig' {
42 | var language: string
43 | export default language
44 | }
45 |
46 | declare module 'remark-macro' {
47 | type Transformer = (content: string, props: any) => any
48 | type InlineTransformer = (props: any) => any
49 | interface Macro {
50 | addMacro(name: string, fn: Transformer, inline: false): void
51 | addMacro(name: string, fn: InlineTransformer, inline: true): void
52 |
53 | transformer: any
54 | }
55 |
56 | var macro: () => Macro
57 | export default macro
58 | }
59 |
60 | declare module '**.ttf' {
61 | var fontUrl: string
62 | export default fontUrl
63 | }
64 |
65 | declare module 'react-markdown/with-html' {
66 | import ReactMarkdown from 'react-markdown'
67 |
68 | export default ReactMarkdown
69 | }
70 |
71 | declare module '@mdx-js/runtime' {
72 | import { FunctionComponent, Component } from 'react'
73 |
74 | type MDXProps = {
75 | scope?: object
76 | components?: Record>
77 | remarkPlugins?: Array
78 | rehypePlugins?: Array
79 | children: string
80 | }
81 |
82 | var MDX: FunctionComponent
83 |
84 | export default MDX
85 | }
86 |
87 | declare module 'remark-custom-blocks' {
88 | var plugin: any
89 |
90 | export default plugin
91 | }
92 |
93 | declare module '@microlink/react' {
94 | var microlink: FuncitonComponent<{
95 | url: string
96 | [key: string]: string
97 | }>
98 |
99 | export default microlink
100 | }
101 |
--------------------------------------------------------------------------------
/src/components/Code/themes/vs.ts:
--------------------------------------------------------------------------------
1 | import { css } from 'emotion'
2 |
3 | export const vs = css`
4 | /**
5 | * VS theme by Andrew Lock (https://andrewlock.net)
6 | * Inspired by Visual Studio syntax coloring
7 | */
8 |
9 | & > .token.comment,
10 | & > .token.prolog,
11 | & > .token.doctype,
12 | & > .token.cdata {
13 | color: #008000;
14 | font-style: italic;
15 | }
16 |
17 | & > .token.namespace {
18 | opacity: 0.7;
19 | }
20 |
21 | & > .token.string {
22 | color: #a31515;
23 | }
24 |
25 | & > .token.punctuation,
26 | & > .token.operator {
27 | color: #393a34; /* no highlight */
28 | }
29 |
30 | & > .token.url,
31 | & > .token.symbol,
32 | & > .token.number,
33 | & > .token.boolean,
34 | & > .token.variable,
35 | & > .token.constant,
36 | & > .token.inserted {
37 | color: #36acaa;
38 | }
39 |
40 | & > .token.atrule,
41 | & > .token.keyword,
42 | & > .token.attr-value,
43 | & > .language-autohotkey .token.selector,
44 | & > .language-json .token.boolean,
45 | & > .language-json .token.number {
46 | color: #0000ff;
47 | }
48 |
49 | & > .token.function {
50 | color: #393a34;
51 | }
52 | & > .token.deleted,
53 | & > .language-autohotkey .token.tag {
54 | color: #9a050f;
55 | }
56 |
57 | & > .token.selector,
58 | & > .language-autohotkey .token.keyword {
59 | color: #00009f;
60 | }
61 |
62 | & > .token.important,
63 | & > .token.bold {
64 | font-weight: bold;
65 | }
66 |
67 | & > .token.italic {
68 | font-style: italic;
69 | }
70 |
71 | & > .token.class-name,
72 | & > .language-json .token.property {
73 | color: #2b91af;
74 | }
75 |
76 | & > .token.tag,
77 | & > .token.selector {
78 | color: #800000;
79 | }
80 |
81 | & > .token.attr-name,
82 | & > .token.property,
83 | & > .token.regex,
84 | & > .token.entity {
85 | color: #ff0000;
86 | }
87 |
88 | & > .token.directive.tag .tag {
89 | background: #ffff00;
90 | color: #393a34;
91 | }
92 |
93 | /* overrides color-values for the Line Numbers plugin
94 | * http://prismjs.com/plugins/line-numbers/
95 | */
96 | & > .line-numbers .line-numbers-rows {
97 | border-right-color: #a5a5a5;
98 | }
99 |
100 | & > .line-numbers-rows > span:before {
101 | color: #2b91af;
102 | }
103 |
104 | /* overrides color-values for the Line Highlight plugin
105 | * http://prismjs.com/plugins/line-highlight/
106 | */
107 | & > .line-highlight {
108 | background: rgba(193, 222, 241, 0.2);
109 | background: -webkit-linear-gradient(
110 | left,
111 | rgba(193, 222, 241, 0.2) 70%,
112 | rgba(221, 222, 241, 0)
113 | );
114 | background: linear-gradient(
115 | to right,
116 | rgba(193, 222, 241, 0.2) 70%,
117 | rgba(221, 222, 241, 0)
118 | );
119 | }
120 | `
121 |
--------------------------------------------------------------------------------
/src/admonition.css:
--------------------------------------------------------------------------------
1 | .admonition {
2 | box-shadow: 0 2px 2px 0 rgba(0, 0, 0, 0.14), 0 1px 5px 0 rgba(0, 0, 0, 0.12), 0 3px 1px -2px rgba(0, 0, 0, 0.2);
3 | position: relative;
4 | margin: 1.5625em 0;
5 | padding: 0 1.2rem;
6 | border-left: 0.4rem solid #448aff;
7 | border-radius: 0.2rem;
8 | }
9 | .admonition > summary {
10 | cursor: pointer;
11 | }
12 | .admonition > .custom-block-body {
13 | margin: 1em 0;
14 | }
15 | .admonition-title,
16 | .admonition-note > .custom-block-heading,
17 | .admonition-info > .custom-block-heading,
18 | .admonition-danger > .custom-block-heading,
19 | .admonition-warning > .custom-block-heading,
20 | .admonition-success > .custom-block-heading,
21 | .admonition-fail > .custom-block-heading,
22 | .admonition-question > .custom-block-heading,
23 | .admonition-abstract > .custom-block-heading,
24 | .admonition-example > .custom-block-heading,
25 | .admonition-spoiler > .custom-block-heading {
26 | margin: 0 -1.2rem;
27 | padding: 0.8rem 1.2rem 0.8rem 1.2rem;
28 | border-bottom: 0.1rem solid rgba(68, 138, 255, 0.1);
29 | background-color: rgba(68, 138, 255, 0.1);
30 | font-weight: 700;
31 | }
32 | .admonition-note {
33 | box-shadow: 0 2px 2px 0 rgba(0, 0, 0, 0.14), 0 1px 5px 0 rgba(0, 0, 0, 0.12), 0 3px 1px -2px rgba(0, 0, 0, 0.2);
34 | position: relative;
35 | margin: 1.5625em 0;
36 | padding: 0 1.2rem;
37 | border-left: 0.4rem solid #448aff;
38 | border-radius: 0.2rem;
39 | border-left-color: #448aff;
40 | }
41 | .admonition-note > summary {
42 | cursor: pointer;
43 | }
44 | .admonition-note > .custom-block-body {
45 | margin: 1em 0;
46 | }
47 | .admonition-note > .custom-block-heading {
48 | background-color: rgba(68, 138, 255, 0.1);
49 | }
50 | .admonition-info {
51 | box-shadow: 0 2px 2px 0 rgba(0, 0, 0, 0.14), 0 1px 5px 0 rgba(0, 0, 0, 0.12), 0 3px 1px -2px rgba(0, 0, 0, 0.2);
52 | position: relative;
53 | margin: 1.5625em 0;
54 | padding: 0 1.2rem;
55 | border-left: 0.4rem solid #448aff;
56 | border-radius: 0.2rem;
57 | border-left-color: #009688;
58 | }
59 | .admonition-info > summary {
60 | cursor: pointer;
61 | }
62 | .admonition-info > .custom-block-body {
63 | margin: 1em 0;
64 | }
65 | .admonition-info > .custom-block-heading {
66 | background-color: rgba(0, 150, 136, 0.1);
67 | }
68 | .admonition-danger {
69 | box-shadow: 0 2px 2px 0 rgba(0, 0, 0, 0.14), 0 1px 5px 0 rgba(0, 0, 0, 0.12), 0 3px 1px -2px rgba(0, 0, 0, 0.2);
70 | position: relative;
71 | margin: 1.5625em 0;
72 | padding: 0 1.2rem;
73 | border-left: 0.4rem solid #448aff;
74 | border-radius: 0.2rem;
75 | border-left-color: #c2185b;
76 | }
77 | .admonition-danger > summary {
78 | cursor: pointer;
79 | }
80 | .admonition-danger > .custom-block-body {
81 | margin: 1em 0;
82 | }
83 | .admonition-danger > .custom-block-heading {
84 | background-color: rgba(194, 24, 91, 0.1);
85 | }
86 | .admonition-warning {
87 | box-shadow: 0 2px 2px 0 rgba(0, 0, 0, 0.14), 0 1px 5px 0 rgba(0, 0, 0, 0.12), 0 3px 1px -2px rgba(0, 0, 0, 0.2);
88 | position: relative;
89 | margin: 1.5625em 0;
90 | padding: 0 1.2rem;
91 | border-left: 0.4rem solid #448aff;
92 | border-radius: 0.2rem;
93 | border-left-color: #ff9100;
94 | }
95 | .admonition-warning > summary {
96 | cursor: pointer;
97 | }
98 | .admonition-warning > .custom-block-body {
99 | margin: 1em 0;
100 | }
101 | .admonition-warning > .custom-block-heading {
102 | background-color: rgba(255, 145, 0, 0.1);
103 | }
104 | .admonition-success {
105 | box-shadow: 0 2px 2px 0 rgba(0, 0, 0, 0.14), 0 1px 5px 0 rgba(0, 0, 0, 0.12), 0 3px 1px -2px rgba(0, 0, 0, 0.2);
106 | position: relative;
107 | margin: 1.5625em 0;
108 | padding: 0 1.2rem;
109 | border-left: 0.4rem solid #448aff;
110 | border-radius: 0.2rem;
111 | border-left-color: #00c853;
112 | }
113 | .admonition-success > summary {
114 | cursor: pointer;
115 | }
116 | .admonition-success > .custom-block-body {
117 | margin: 1em 0;
118 | }
119 | .admonition-success > .custom-block-heading {
120 | background-color: rgba(0, 200, 83, 0.1);
121 | }
122 | .admonition-fail {
123 | box-shadow: 0 2px 2px 0 rgba(0, 0, 0, 0.14), 0 1px 5px 0 rgba(0, 0, 0, 0.12), 0 3px 1px -2px rgba(0, 0, 0, 0.2);
124 | position: relative;
125 | margin: 1.5625em 0;
126 | padding: 0 1.2rem;
127 | border-left: 0.4rem solid #448aff;
128 | border-radius: 0.2rem;
129 | border-left-color: #d32f2f;
130 | }
131 | .admonition-fail > summary {
132 | cursor: pointer;
133 | }
134 | .admonition-fail > .custom-block-body {
135 | margin: 1em 0;
136 | }
137 | .admonition-fail > .custom-block-heading {
138 | background-color: rgba(211, 47, 47, 0.1);
139 | }
140 | .admonition-question {
141 | box-shadow: 0 2px 2px 0 rgba(0, 0, 0, 0.14), 0 1px 5px 0 rgba(0, 0, 0, 0.12), 0 3px 1px -2px rgba(0, 0, 0, 0.2);
142 | position: relative;
143 | margin: 1.5625em 0;
144 | padding: 0 1.2rem;
145 | border-left: 0.4rem solid #448aff;
146 | border-radius: 0.2rem;
147 | border-left-color: #64dd17;
148 | }
149 | .admonition-question > summary {
150 | cursor: pointer;
151 | }
152 | .admonition-question > .custom-block-body {
153 | margin: 1em 0;
154 | }
155 | .admonition-question > .custom-block-heading {
156 | background-color: rgba(100, 221, 23, 0.1);
157 | }
158 | .admonition-abstract {
159 | box-shadow: 0 2px 2px 0 rgba(0, 0, 0, 0.14), 0 1px 5px 0 rgba(0, 0, 0, 0.12), 0 3px 1px -2px rgba(0, 0, 0, 0.2);
160 | position: relative;
161 | margin: 1.5625em 0;
162 | padding: 0 1.2rem;
163 | border-left: 0.4rem solid #448aff;
164 | border-radius: 0.2rem;
165 | border-left-color: #00b0ff;
166 | }
167 | .admonition-abstract > summary {
168 | cursor: pointer;
169 | }
170 | .admonition-abstract > .custom-block-body {
171 | margin: 1em 0;
172 | }
173 | .admonition-abstract > .custom-block-heading {
174 | background-color: rgba(0, 176, 255, 0.1);
175 | }
176 | .admonition-example {
177 | box-shadow: 0 2px 2px 0 rgba(0, 0, 0, 0.14), 0 1px 5px 0 rgba(0, 0, 0, 0.12), 0 3px 1px -2px rgba(0, 0, 0, 0.2);
178 | position: relative;
179 | margin: 1.5625em 0;
180 | padding: 0 1.2rem;
181 | border-left: 0.4rem solid #448aff;
182 | border-radius: 0.2rem;
183 | border-left-color: #651fff;
184 | }
185 | .admonition-example > summary {
186 | cursor: pointer;
187 | }
188 | .admonition-example > .custom-block-body {
189 | margin: 1em 0;
190 | }
191 | .admonition-example > .custom-block-heading {
192 | background-color: rgba(101, 31, 255, 0.1);
193 | }
194 | .admonition-spoiler {
195 | box-shadow: 0 2px 2px 0 rgba(0, 0, 0, 0.14), 0 1px 5px 0 rgba(0, 0, 0, 0.12), 0 3px 1px -2px rgba(0, 0, 0, 0.2);
196 | position: relative;
197 | margin: 1.5625em 0;
198 | padding: 0 1.2rem;
199 | border-left: 0.4rem solid #448aff;
200 | border-radius: 0.2rem;
201 | border-left-color: #455a64;
202 | }
203 | .admonition-spoiler > summary {
204 | cursor: pointer;
205 | }
206 | .admonition-spoiler > .custom-block-body {
207 | margin: 1em 0;
208 | }
209 | .admonition-spoiler > .custom-block-heading {
210 | padding-left: 1rem;
211 | background-color: rgba(69, 90, 100, 0.1);
212 | }
213 |
214 | .custom-block-body {
215 | overflow: auto;
216 | }
217 |
--------------------------------------------------------------------------------