├── .gitignore
├── LICENSE
├── README.md
├── components
├── ReactBricksApp.tsx
├── errorNoFooter.tsx
├── errorNoHeader.tsx
├── errorNoKeys.tsx
└── layout.tsx
├── css
├── Button.module.css
├── FeatureItem.module.css
├── Features.module.css
├── Footer.module.css
├── FooterColumn.module.css
├── FooterLink.module.css
├── Header.module.css
├── HeaderMenuItem.module.css
├── HeaderMenuSubItem.module.css
├── HeroUnit.module.css
├── Pokemon.module.css
├── errorNoFooter.module.css
├── errorNoHeader.module.css
├── errorNoKeys.module.css
├── layout.module.css
└── style.css
├── next-env.d.ts
├── next.config.js
├── package.json
├── pages
├── [[...slug]].tsx
├── _app.tsx
├── admin
│ ├── app-settings.tsx
│ ├── editor.tsx
│ ├── index.tsx
│ ├── media.tsx
│ ├── playground.tsx
│ ├── sso-failure.tsx
│ ├── sso-login.tsx
│ └── sso-success.tsx
└── preview.tsx
├── public
├── favicon.ico
├── logo.svg
├── react-bricks-icon.svg
└── react-bricks-logo.svg
├── react-bricks
├── NextLink.tsx
├── bricks
│ ├── HeroUnit.tsx
│ ├── features
│ │ ├── FeatureItem.tsx
│ │ ├── Features.tsx
│ │ ├── defaultImages.ts
│ │ └── index.ts
│ ├── index.ts
│ └── layout
│ │ ├── Button.tsx
│ │ ├── Footer.tsx
│ │ ├── FooterColumn.tsx
│ │ ├── FooterLink.tsx
│ │ ├── Header.tsx
│ │ ├── HeaderMenuItem.tsx
│ │ ├── HeaderMenuSubItem.tsx
│ │ ├── index.ts
│ │ └── useClickOutside.ts
├── config.ts
└── pageTypes.ts
└── tsconfig.json
/.gitignore:
--------------------------------------------------------------------------------
1 | # See https://help.github.com/articles/ignoring-files/ for more about ignoring files.
2 |
3 | # dependencies
4 | /node_modules
5 | /.pnp
6 | .pnp.js
7 |
8 | # testing
9 | /coverage
10 |
11 | # next.js
12 | /.next/
13 | /out/
14 |
15 | # production
16 | /build
17 |
18 | # misc
19 | .DS_Store
20 | .env*
21 |
22 | # debug
23 | npm-debug.log*
24 | yarn-debug.log*
25 | yarn-error.log*
26 |
27 | # lock files
28 | yarn.lock
29 | pnpm-lock.yaml
30 | package-lock.json
31 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | Copyright (c) 2023 React Bricks
2 |
3 | Permission is hereby granted, free of charge, to any user of the React Bricks
4 | services, to use this starter project and the included pre-made content blocks
5 | in order to create a website using the React Bricks services.
6 | This is a "source available" license.
7 |
8 | As for any part of the React Bricks services, the use is subject to the
9 | acceptance of the general Terms of Service, which can be found at:
10 | https://reactbricks.com/legal/terms
11 |
12 | In particular, the users may not use this project for the purpose of (i)
13 | building a competitive product or service, (ii) building a product using
14 | similar ideas, features, functions, user interface of graphics of React
15 | Bricks Services, (iii) copying any ideas, features, functions, user
16 | interface or graphics of the React Bricks Services.
17 |
18 | The above copyright notice and this permission notice shall be included in all
19 | copies or substantial portions of the Software.
20 |
21 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
22 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
23 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
24 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
25 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
26 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
27 | SOFTWARE.
28 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # React Bricks starter with Next.js
2 |
3 | Kick-start your project with this boilerplate for a complete Next.js website based on [React Bricks](https://reactbricks.com), with both the front-end and admin dashboard.
4 |
5 | ## 🚀 Quick start
6 |
7 | We suggest that you use the CLI and choose this starter.
8 | In this way you will have the credentials already set up in a `.env.local` file:
9 |
10 | ```bash
11 | npx create-reactbricks-app
12 | ```
13 |
14 | Otherwise you can directly clone this repo:
15 |
16 | ```bash
17 | git clone https://github.com/reactbricks/nextjs-starter-reactbricks your-project
18 | ```
19 |
20 | ## 📖 Documentation
21 |
22 | Please, read our documentation at [Reactbricks.com](https://reactbricks.com).
23 |
--------------------------------------------------------------------------------
/components/ReactBricksApp.tsx:
--------------------------------------------------------------------------------
1 | import { useEffect, useState } from 'react'
2 | import { ReactBricks } from 'react-bricks/frontend'
3 | import type { AppProps } from 'next/app'
4 | import { Nunito_Sans } from 'next/font/google'
5 | import config from '../react-bricks/config'
6 | import { useTheme } from 'next-themes'
7 |
8 | const nunito = Nunito_Sans({
9 | subsets: ['latin'],
10 | display: 'swap',
11 | weight: ['300', '400', '600', '700', '800', '900'],
12 | style: ['normal', 'italic'],
13 | variable: '--font-nunito',
14 | })
15 |
16 | const ReactBricksApp = ({ Component, pageProps }: AppProps) => {
17 | // Color Mode Management
18 | const savedColorMode =
19 | typeof window === 'undefined' ? '' : localStorage.getItem('color-mode')
20 |
21 | const [colorMode, setColorMode] = useState(savedColorMode || 'light')
22 |
23 | const { setTheme } = useTheme()
24 |
25 | const toggleColorMode = () => {
26 | const newColorMode = colorMode === 'light' ? 'dark' : 'light'
27 | setColorMode(newColorMode)
28 | localStorage.setItem('color-mode', newColorMode)
29 | setTheme(newColorMode)
30 | }
31 |
32 | const reactBricksConfig = {
33 | ...config,
34 | isDarkColorMode: colorMode === 'dark',
35 | toggleColorMode,
36 | contentClassName: `${nunito.className} ${colorMode} ${
37 | colorMode === 'dark' ? 'dark darkContentClass' : 'light whiteContentClass'
38 | }`,
39 | }
40 |
41 | return (
42 |
43 |
44 |
45 | )
46 | }
47 |
48 | export default ReactBricksApp
49 |
--------------------------------------------------------------------------------
/components/errorNoFooter.tsx:
--------------------------------------------------------------------------------
1 | import styles from "../css/errorNoFooter.module.css"
2 |
3 | const ErrorNoFooter = () => {
4 | return (
5 |
6 |
Warning: there is no footer.
7 |
8 | React Bricks cannot find an entity for the footer.
9 |
10 |
11 | )
12 | }
13 |
14 | export default ErrorNoFooter
15 |
--------------------------------------------------------------------------------
/components/errorNoHeader.tsx:
--------------------------------------------------------------------------------
1 | import styles from "../css/errorNoHeader.module.css"
2 |
3 | const ErrorNoHeader = () => {
4 | return (
5 |
6 |
Warning: there is no header.
7 |
8 | React Bricks cannot find an entity for the header.
9 |
10 |
11 | )
12 | }
13 |
14 | export default ErrorNoHeader
15 |
--------------------------------------------------------------------------------
/components/errorNoKeys.tsx:
--------------------------------------------------------------------------------
1 | import styles from "../css/errorNoKeys.module.css"
2 |
3 | const ErrorNoKeys = () => {
4 | return (
5 |
6 |
Warning: missing App credentials
7 |
8 | NEXT_PUBLIC_APP_ID
and{" "}
9 | API_KEY
are not configured in
10 | your .env.local
file.
11 |
12 |
13 | Please create a .env.local
{" "}
14 | file with:
15 |
16 |
17 | {`NEXT_PUBLIC_APP_ID=...
18 | API_KEY=...`}
19 |
20 |
21 | )
22 | }
23 |
24 | export default ErrorNoKeys
25 |
--------------------------------------------------------------------------------
/components/layout.tsx:
--------------------------------------------------------------------------------
1 | import React, { ReactNode, useContext, useEffect, useState } from 'react'
2 | import { Nunito_Sans } from 'next/font/google'
3 | import styles from '../css/layout.module.css'
4 |
5 | interface LayoutProps {
6 | children?: ReactNode
7 | }
8 |
9 | const nunito = Nunito_Sans({
10 | subsets: ['latin'],
11 | display: 'swap',
12 | weight: ['300', '400', '600', '700', '800', '900'],
13 | style: ['normal', 'italic'],
14 | variable: '--font-nunito',
15 | })
16 |
17 | const Layout: React.FC = ({ children }) => {
18 | return (
19 |
20 | {children}
21 |
22 | )
23 | }
24 |
25 | export default Layout
26 |
--------------------------------------------------------------------------------
/css/Button.module.css:
--------------------------------------------------------------------------------
1 | .buttonWrapper {
2 | display: inline-block;
3 | white-space: nowrap;
4 | text-align: center;
5 | border-radius: 9999px;
6 | font-weight: 700;
7 | line-height: 1;
8 | transition-property: all;
9 | transition-timing-function: cubic-bezier(0, 0, 0.2, 1);
10 | transition-duration: 150ms;
11 | }
12 |
13 | .buttonWrapper:hover {
14 | box-shadow: 0 10px 15px -3px rgb(0 0 0 / 0.1), 0 4px 6px -4px rgb(0 0 0 / 0.1);
15 | transform: translateY(-0.125rem);
16 | }
17 |
18 | .buttonPsmall {
19 | padding-top: 0.5rem;
20 | padding-bottom: 0.5rem;
21 | padding-left: 1rem;
22 | padding-right: 1rem;
23 | font-size: 0.875rem;
24 | line-height: 1.25rem;
25 | min-width: 75px;
26 | }
27 |
28 | .buttonPnormal {
29 | padding-top: 0.75rem;
30 | padding-bottom: 0.75rem;
31 | padding-left: 1.25rem;
32 | padding-right: 1.25rem;
33 | min-width: 120px;
34 | }
35 |
36 | .buttonColorSolid {
37 | background-color: rgb(14 165 233);
38 | color: white;
39 | }
40 | .buttonColorSolid:hover {
41 | background-color: rgb(2 132 199);
42 | }
43 |
44 | .buttonColorOutline {
45 | border-width: 1px;
46 | border-color: rgb(2 132 199);
47 | color: rgb(2 132 199);
48 | }
49 | :global(.dark) .buttonColorOutline {
50 | border-color: rgb(255 255 255);
51 | color: white;
52 | }
53 |
--------------------------------------------------------------------------------
/css/FeatureItem.module.css:
--------------------------------------------------------------------------------
1 | .cols2,
2 | .cols3,
3 | .cols4 {
4 | margin-bottom: 3rem;
5 | }
6 |
7 | .featureItemContainer {
8 | font-size: 1rem;
9 | line-height: 1.5rem;
10 | }
11 |
12 | .imageClassName {
13 | display: block;
14 | width: 3rem;
15 | height: 3rem;
16 | object-fit: contain;
17 | }
18 |
19 | .imageWrapper {
20 | float: left;
21 | margin-right: 1.25rem;
22 | margin-top: 0.25rem;
23 | }
24 |
25 | .textFeatureItemContainer {
26 | overflow: hidden;
27 | }
28 |
29 | .title {
30 | font-weight: 700;
31 | margin-bottom: 0.25rem;
32 | color: rgb(31 41 55);
33 | }
34 |
35 | :global(.dark) .title {
36 | color: white;
37 | }
38 |
39 | .textColor {
40 | color: rgb(107 114 128);
41 | }
42 |
43 | :global(.dark) .textColor {
44 | color: white;
45 | }
46 |
47 | .linkContainer {
48 | margin-top: 0.5rem;
49 | }
50 |
51 | .linkWrapper {
52 | cursor: pointer;
53 | color: rgb(14 165 233);
54 | transition-property: all;
55 | transition-timing-function: cubic-bezier(0.4, 0, 0.2, 1);
56 | transition-duration: 150ms;
57 | }
58 |
59 | .linkWrapper:hover {
60 | color: rgb(2 132 199);
61 | transform: translateY(-1px);
62 | }
63 |
64 | .linkTextPlain1 {
65 | display: flex;
66 | align-items: center;
67 | }
68 |
69 | .linkTextPlain1 > :not([hidden]) ~ :not([hidden]) {
70 | margin-left: 0.25rem;
71 | }
72 |
73 | .svgClass {
74 | width: 10px;
75 | height: 10px;
76 | }
77 |
78 | .linkTextPlain2 {
79 | display: inline-block;
80 | }
81 |
82 | .linkTextPlain3 {
83 | display: none;
84 | }
85 |
86 | @media (min-width: 640px) {
87 | .cols2 {
88 | flex: 0 1 45%;
89 | margin-bottom: 4rem;
90 | }
91 |
92 | .cols3 {
93 | flex: 0 1 27%;
94 | margin-bottom: 4rem;
95 | }
96 |
97 | .cols4 {
98 | flex: 0 1 45%;
99 | margin-bottom: 4rem;
100 | }
101 |
102 | .imageWrapper {
103 | float: none;
104 | margin-right: 0;
105 | margin-top: 0;
106 | margin-bottom: 1.25rem;
107 | }
108 | }
109 |
110 | @media (min-width: 1024px) {
111 | .cols4 {
112 | flex: 0 1 20.1%;
113 | }
114 | }
115 |
--------------------------------------------------------------------------------
/css/Features.module.css:
--------------------------------------------------------------------------------
1 | .section {
2 | background-color: white;
3 | }
4 |
5 | :global(.dark) .section {
6 | background-color: rgb(17 24 39);
7 | }
8 |
9 | .container {
10 | display: flex;
11 | flex-wrap: wrap;
12 | justify-content: space-between;
13 | padding-top: 3rem;
14 | padding-bottom: 3rem;
15 | }
16 |
17 | .sizeSmall {
18 | padding-left: 1.25rem;
19 | padding-right: 1.25rem;
20 | }
21 |
22 | .sizeNormal {
23 | padding-left: 1.25rem;
24 | padding-right: 1.25rem;
25 | }
26 |
27 | @media (min-width: 640px) {
28 | .sizeSmall {
29 | margin-right: 16.66666%;
30 | margin-left: 16.66666%;
31 | }
32 |
33 | .sizeNormal {
34 | margin-right: 5.55555%;
35 | margin-left: 5.55555%;
36 | }
37 | }
38 |
39 | @media (min-width: 1024px) {
40 | .container {
41 | padding-top: 4rem;
42 | padding-bottom: 4rem;
43 | }
44 | }
45 |
46 | @media (min-width: 1280px) {
47 | .sizeSmall {
48 | margin-right: 22.2222%;
49 | margin-left: 22.2222%;
50 | }
51 | .sizeNormal {
52 | margin-right: 11.1111%;
53 | margin-left: 11.1111%;
54 | }
55 | }
56 |
--------------------------------------------------------------------------------
/css/Footer.module.css:
--------------------------------------------------------------------------------
1 | .section {
2 | background-color: #f9fafb;
3 | }
4 |
5 | :global(.dark) .section {
6 | background-color: rgb(17 24 39);
7 | }
8 |
9 | .container {
10 | display: flex;
11 | justify-content: space-between;
12 | flex-wrap: wrap;
13 | padding-top: 3rem;
14 | padding-bottom: 3rem;
15 | padding-left: 1.25rem;
16 | padding-right: 1.25rem;
17 | }
18 |
19 | @media (min-width: 640px) {
20 | .container {
21 | margin-left: 5.55555%;
22 | margin-right: 5.55555%;
23 | }
24 | }
25 |
26 | @media (min-width: 1280px) {
27 | .container {
28 | margin-left: 11.1111%;
29 | margin-right: 11.1111%;
30 | }
31 | }
32 |
33 | .elementsInfo {
34 | width: 100%;
35 | margin-bottom: 3rem;
36 | }
37 |
38 | @media (min-width: 1024px) {
39 | .elementsInfo {
40 | width: auto;
41 | margin-bottom: 0px;
42 | margin-right: 2rem;
43 | }
44 |
45 | .container {
46 | padding-top: 4rem;
47 | padding-bottom: 4rem;
48 | }
49 | }
50 |
51 | .linkLogo {
52 | display: block;
53 | margin-bottom: 1rem;
54 | }
55 |
56 | .imageLogo {
57 | width: 12rem;
58 | height: 1.75rem;
59 | object-fit: contain;
60 | object-position: left;
61 | }
62 |
63 | .paragraphRichText {
64 | font-size: 0.875rem;
65 | line-height: 1.25rem;
66 | color: rgb(107 114 128);
67 | }
68 |
69 | :global(.dark) .paragraphRichText {
70 | color: white;
71 | }
72 |
73 | .renderLink {
74 | color: rgb(14 165 233);
75 | transition-property: all;
76 | transition-timing-function: cubic-bezier(0, 0, 0.2, 1);
77 | transition-duration: 150ms;
78 | }
79 |
80 | .renderLink:hover {
81 | color: rgb(2 132 199);
82 | transform: translateY(-1px);
83 | }
84 |
85 |
--------------------------------------------------------------------------------
/css/FooterColumn.module.css:
--------------------------------------------------------------------------------
1 | .container {
2 | width: 50%;
3 | margin-bottom: 2rem;
4 | }
5 |
6 | @media (min-width: 640px) {
7 | .container {
8 | width: auto;
9 | margin-right: 2rem;
10 | }
11 | }
12 |
13 | .text {
14 | margin-bottom: 0.75rem;
15 | font-size: 0.75rem;
16 | line-height: 1rem;
17 | font-weight: 900;
18 | text-transform: uppercase;
19 | letter-spacing: 0.35em;
20 | min-width: 120px;
21 | color: rgb(156 163 175);
22 | }
23 |
24 | :global(.dark) .text {
25 | color: rgb(243 244 246);
26 | }
27 |
--------------------------------------------------------------------------------
/css/FooterLink.module.css:
--------------------------------------------------------------------------------
1 | .text {
2 | font-size: 0.875rem;
3 | line-height: 1.25rem;
4 | margin-bottom: 0.75rem;
5 | color: rgb(107 114 128);
6 | transition-property: all;
7 | transition-timing-function: cubic-bezier(0, 0, 0.2, 1);
8 | transition-duration: 150ms;
9 | }
10 |
11 | .text:hover {
12 | color: rgb(75 85 99);
13 | transform: translateY(-1px);
14 | }
15 |
16 | :global(.dark) .text {
17 | color: white;
18 | }
19 |
--------------------------------------------------------------------------------
/css/Header.module.css:
--------------------------------------------------------------------------------
1 | .section {
2 | background-color: white;
3 | }
4 |
5 | :global(.dark) .section {
6 | background-color: rgb(17 24 39);
7 | }
8 |
9 | .navClass {
10 | display: flex;
11 | justify-content: center;
12 | align-items: center;
13 | padding: 1.25rem;
14 | }
15 |
16 | .linkLogo {
17 | display: inline-flex;
18 | padding-top: 0.375rem;
19 | padding-bottom: 0.375rem;
20 | padding-left: 0.5rem;
21 | padding-right: 0.5rem;
22 | margin-right: 1.5rem;
23 | }
24 |
25 | .imageClass {
26 | display: block;
27 | width: 8rem;
28 | height: 1.75rem;
29 | object-fit: contain;
30 | object-position: left;
31 | }
32 |
33 | .containerMenuItems {
34 | display: none;
35 | align-items: center;
36 | }
37 | .containerMenuItems > :not([hidden]) ~ :not([hidden]) {
38 | margin-left: 0.5rem;
39 | }
40 |
41 | .containerButtons {
42 | display: none;
43 | margin-left: auto;
44 | }
45 |
46 | .buttonsWrapper {
47 | display: flex;
48 | flex-direction: row;
49 | align-items: center;
50 | justify-content: flex-end;
51 | }
52 |
53 | .buttonsWrapper > :not([hidden]) ~ :not([hidden]) {
54 | margin-left: 1.25rem;
55 | }
56 |
57 | .containerHamburgerMenu {
58 | position: relative;
59 | display: flex;
60 | height: 100%;
61 | align-items: center;
62 | }
63 |
64 | .buttonHamburgerMenu {
65 | display: flex;
66 | justify-content: center;
67 | align-items: center;
68 | padding: 0.25rem;
69 | width: 1.75rem;
70 | height: 1.75rem;
71 | border-radius: 5px;
72 | }
73 |
74 | .buttonHamburgerMenu:hover {
75 | background-color: rgb(14 165 233 / 0.2);
76 | color: rgb(2 132 199);
77 | }
78 |
79 | .buttonHamburgerMenu:focus {
80 | background-color: rgb(14 165 233 / 0.2);
81 | color: rgb(2 132 199);
82 | }
83 |
84 | :global(.dark) .buttonHamburgerMenu {
85 | background-color: rgb(17 24 39);
86 | }
87 |
88 | :global(.dark) .buttonHamburgerMenu:hover {
89 | background-color: rgb(14 165 233 / 0.4);
90 | color: white;
91 | }
92 |
93 | :global(.dark) .buttonHamburgerMenu:focus {
94 | background-color: rgb(14 165 233 / 0.4);
95 | color: white;
96 | }
97 |
98 | .containerHamburgerMenuItems {
99 | position: absolute;
100 | top: 2rem;
101 | right: 0px;
102 | width: 16rem;
103 | background-color: white;
104 | padding: 1.25rem;
105 | border-width: 1px;
106 | border-radius: 0.5rem;
107 | box-shadow: 0 10px 15px -3px rgb(0 0 0 / 0.1), 0 4px 6px -4px rgb(0 0 0 / 0.1);
108 | z-index: 10;
109 | }
110 |
111 | .darkModeButton {
112 | display: flex;
113 | align-items: center;
114 | justify-content: center;
115 | width: 2rem;
116 | height: 2rem;
117 | margin-right: 1rem;
118 | margin-left: auto;
119 | cursor: pointer;
120 | background-color: transparent;
121 | color: rgb(156 163 175);
122 | }
123 |
124 | :global(.dark) .darkModeButton {
125 | color: rgb(229 231 235);
126 | }
127 |
128 | .hamburgerMenuFiX {
129 | color: rgb(75 85 99);
130 | }
131 |
132 | .hamburgerMenuFiMenu {
133 | color: rgb(75 85 99);
134 | }
135 |
136 | :global(.dark) .hamburgerMenuFiX {
137 | color: white;
138 | }
139 |
140 | :global(.dark) .hamburgerMenuFiMenu {
141 | color: white;
142 | }
143 |
144 | @media (min-width: 640px) {
145 | .navClass {
146 | margin-left: 5.55555%;
147 | margin-right: 5.55555%;
148 | }
149 |
150 | .containerHamburgerMenu {
151 | gap: 10px;
152 | }
153 | }
154 |
155 | @media (min-width: 1024px) {
156 | .darkModeButton{
157 | margin-left: 2rem;
158 | }
159 | .containerMenuItems {
160 | display: flex;
161 | }
162 | .containerButtons {
163 | display: block;
164 | }
165 | .containerHamburgerMenu {
166 | display: none;
167 | }
168 | }
169 |
170 | @media (min-width: 1280px) {
171 | .navClass {
172 | margin-left: 11.1111%;
173 | margin-right: 11.1111%;
174 | }
175 | }
176 |
--------------------------------------------------------------------------------
/css/HeaderMenuItem.module.css:
--------------------------------------------------------------------------------
1 | .linkMenuItem {
2 | display: none;
3 | justify-content: center;
4 | align-items: center;
5 | font-size: 0.875rem;
6 | line-height: 1.25rem;
7 | font-weight: 700;
8 | padding-top: 0.375rem;
9 | padding-bottom: 0.375rem;
10 | padding-left: 0.5rem;
11 | padding-right: 0.5rem;
12 | border-radius: 5px;
13 | transition-property: color, background-color, border-color,
14 | text-decoration-color, fill, stroke;
15 | transition-duration: 150ms;
16 | transition-timing-function: cubic-bezier(0, 0, 0.2, 1);
17 | color: rgb(75 85 99);
18 | }
19 |
20 | .linkMenuItemActive {
21 | color: rgb(2 132 199);
22 | background-color: rgb(14 165 233 / 0.1);
23 | }
24 |
25 | :global(.dark) .linkMenuItemActive {
26 | color: white;
27 | background-color: rgb(14 165 233 / 0.3);
28 | }
29 |
30 | :global(.dark) .linkMenuItem {
31 | color: white;
32 | }
33 |
34 | .linkMenuItem:hover {
35 | background-color: rgb(14 165 233 / 0.2);
36 | color: rgb(2 132 199);
37 | }
38 |
39 | :global(.dark) .linkMenuItem:hover {
40 | color: white;
41 | background-color: rgb(14 165 233 / 0.4);
42 | }
43 |
44 | .linkHamburgerMenuItem {
45 | display: block;
46 | font-size: 0.875rem;
47 | line-height: 1.25rem;
48 | margin-bottom: 0.75rem;
49 | transition-property: color, background-color, border-color,
50 | text-decoration-color, fill, stroke;
51 | transition-duration: 150ms;
52 | transition-timing-function: cubic-bezier(0, 0, 0.2, 1);
53 | color: rgb(31 41 55);
54 | }
55 |
56 | /*:global(.dark) .linkHamburgerMenuItem {
57 | color: white;
58 | }*/
59 |
60 | .linkHamburgerMenuItem:hover {
61 | color: rgb(2 132 199);
62 | }
63 |
64 | /*:global(.dark) .linkHamburgerMenuItem:hover {
65 | color: rgb(14 165 233);
66 | }*/
67 |
68 | .containerLinkItemWithSubItems {
69 | display: none;
70 | position: relative;
71 | }
72 |
73 | .buttonLinkItemWithSubItems {
74 | display: inline-flex;
75 | justify-content: center;
76 | align-items: center;
77 | font-size: 0.875rem;
78 | font-weight: 700;
79 | line-height: 1.25rem;
80 |
81 | color: rgb(75 85 99);
82 | padding-top: 0.375rem;
83 | padding-bottom: 0.375rem;
84 | padding-left: 0.5rem;
85 | padding-right: 0.5rem;
86 | border-radius: 5px;
87 | transition-property: color, background-color, border-color,
88 | text-decoration-color, fill, stroke;
89 | transition-duration: 150ms;
90 | transition-timing-function: cubic-bezier(0, 0, 0.2, 1);
91 | background-color: transparent;
92 | }
93 |
94 | :global(.dark) .buttonLinkItemWithSubItems {
95 | color: white;
96 | }
97 |
98 | .buttonLinkItemWithSubItems:hover {
99 | background-color: rgb(14 165 233 / 0.2);
100 | color: rgb(2 132 199);
101 | }
102 |
103 | .buttonLinkItemWithSubItems:focus {
104 | background-color: rgb(14 165 233 / 0.2);
105 | color: rgb(2 132 199);
106 | }
107 |
108 | :global(.dark) .buttonLinkItemWithSubItems:hover {
109 | color: white;
110 | background-color: rgb(14 165 233 / 0.4);
111 | }
112 | :global(.dark) .buttonLinkItemWithSubItems:focus {
113 | color: white;
114 | background-color: rgb(14 165 233 / 0.4);
115 | }
116 |
117 | .buttonLinkItemWithSubItemsOpen {
118 | background-color: rgb(14 165 233 / 0.4);
119 | color: rgb(2 132 199);
120 | }
121 |
122 | :global(.dark) .buttonLinkItemWithSubItemsOpen {
123 | color: white;
124 | }
125 |
126 | .buttonTextActive {
127 | color: rgb(2 132 199);
128 | background-color: rgb(14 165 233 / 0.1);
129 | }
130 |
131 | :global(.dark) .buttonTextActive {
132 | color: rgb(56 189 248);
133 | }
134 |
135 | .svgClass {
136 | display: inline-block;
137 | width: 10px;
138 | height: 10px;
139 | margin-left: 5px;
140 | }
141 |
142 | .containerSubmenuItemsOpen {
143 | position: absolute;
144 | top: 2.25rem;
145 | z-index: 10;
146 | width: 16rem;
147 | background-color: white;
148 | padding: 0.75rem;
149 | border-width: 1px;
150 | border-radius: 0.5rem;
151 | box-shadow: 0 10px 15px -3px rgb(0 0 0 / 0.1), 0 4px 6px -4px rgb(0 0 0 / 0.1);
152 | }
153 |
154 | /*:global(.dark) .containerSubmenuItemsOpen {
155 | background-color: rgb(17 24 39);
156 | border-color: rgb(156 163 175);
157 | }*/
158 |
159 | .containerSubmenuItems {
160 | margin-bottom: 1.5rem;
161 | }
162 |
163 | .containerLinkText {
164 | font-size: 0.75rem;
165 | line-height: 1rem;
166 | font-weight: 800;
167 | text-transform: uppercase;
168 | color: rgb(107 114 128);
169 | letter-spacing: 0.35rem;
170 | margin-bottom: 1rem;
171 | }
172 |
173 | /*:global(.dark) .containerLinkText {
174 | color: white;
175 | }*/
176 |
177 | @media (min-width: 1024px) {
178 | .linkMenuItem {
179 | display: inline-flex;
180 | }
181 | .linkHamburgerMenuItem {
182 | display: none;
183 | }
184 | .containerLinkItemWithSubItems {
185 | display: block;
186 | }
187 | .containerSubmenuItems {
188 | display: none;
189 | }
190 | }
191 |
--------------------------------------------------------------------------------
/css/HeaderMenuSubItem.module.css:
--------------------------------------------------------------------------------
1 | .linkContainer {
2 | padding: 0;
3 | margin-bottom: 0.75rem;
4 | display: flex;
5 | align-items: flex-start;
6 | }
7 |
8 | .fiContainer {
9 | color: rgb(14 165 233);
10 | margin-right: 0.5rem;
11 | }
12 |
13 | .textContainer {
14 | flex: 1 1 0%;
15 | overflow: hidden;
16 | }
17 |
18 | .linkContainer:hover .linkText {
19 | color: rgb(2 132 199);
20 | }
21 |
22 | /*:global(.dark) .linkContainer:hover .linkText {
23 | color: rgb(14 165 233);
24 | }*/
25 |
26 | .linkText {
27 | color: rgb(17 24 39);
28 | font-size: 0.875rem;
29 | line-height: 1.25rem;
30 | overflow: hidden;
31 | text-overflow: ellipsis;
32 | white-space: nowrap;
33 | transition-property: color, background-color, border-color,
34 | text-decoration-color, fill, stroke;
35 | transition-duration: 150ms;
36 | transition-timing-function: cubic-bezier(0, 0, 0.2, 1);
37 | }
38 |
39 | /*:global(.dark) .linkText {
40 | color: white;
41 | }*/
42 |
43 | .descriptionContainer {
44 | display: none;
45 | }
46 |
47 | .linkDescription {
48 | color: rgb(75 85 99);
49 | font-size: 0.875rem;
50 | line-height: 1.25rem;
51 | transition-property: color, background-color, border-color,
52 | text-decoration-color, fill, stroke;
53 | transition-duration: 150ms;
54 | transition-timing-function: cubic-bezier(0, 0, 0.2, 1);
55 | }
56 |
57 | /*:global(.dark) .linkDescription {
58 | color: white;
59 | }*/
60 |
61 | @media (min-width: 1024px) {
62 | .linkContainer {
63 | padding: 0.75rem;
64 | }
65 | .fiContainer {
66 | display: none;
67 | }
68 | .textContainer {
69 | overflow: auto;
70 | }
71 | .linkText {
72 | overflow: auto;
73 | white-space: normal;
74 | font-weight: 700;
75 | }
76 | .descriptionContainer {
77 | display: block;
78 | }
79 | }
80 |
--------------------------------------------------------------------------------
/css/HeroUnit.module.css:
--------------------------------------------------------------------------------
1 | .container {
2 | background-color: white;
3 | }
4 |
5 | :global(.dark) .container {
6 | background-color: rgb(17 24 39);
7 | }
8 |
9 | .padding {
10 | max-width: 36rem;
11 | margin-left: auto;
12 | margin-right: auto;
13 | padding-left: 1.5rem;
14 | padding-right: 1.5rem;
15 | }
16 |
17 | .bigPadding {
18 | padding-top: 5rem;
19 | padding-bottom: 5rem;
20 | }
21 |
22 | .smallPadding {
23 | padding-top: 3rem;
24 | padding-bottom: 3rem;
25 | }
26 |
27 | .heroImage {
28 | width: 5rem;
29 | margin-bottom: 1.25rem;
30 | margin-left: auto;
31 | margin-right: auto;
32 | }
33 |
34 | .title {
35 | font-size: 1.875rem;
36 | line-height: 2.25rem;
37 | color: rgb(17 24 39);
38 | text-align: center;
39 | font-weight: 900;
40 | line-height: 1.25;
41 | margin-bottom: 0.75rem;
42 | }
43 |
44 | :global(.dark) .title {
45 | color: rgb(255 255 255);
46 | }
47 |
48 | .placeholderSpan {
49 | opacity: 0.3;
50 | }
51 |
52 | .richText {
53 | font-size: 1.25rem;
54 | line-height: 1.75rem;
55 | text-align: center;
56 | line-height: 1.625;
57 | color: rgb(55 65 81);
58 | }
59 |
60 | :global(.dark) .richText {
61 | color: rgb(243 244 246);
62 | }
63 |
64 | .code {
65 | font-size: 0.875rem;
66 | line-height: 1.25rem;
67 | padding-top: 0.25rem;
68 | padding-bottom: 0.25rem;
69 | padding-left: 0.5rem;
70 | padding-right: 0.5rem;
71 | background-color: rgb(229 231 235);
72 | border-radius: 0.25rem;
73 | }
74 |
75 | :global(.dark) .code {
76 | background-color: rgb(55 65 81);
77 | }
78 |
79 | .richTextLink {
80 | color: rgb(14 165 233);
81 | transition-property: color, background-color, border-color, text-decoration-color, fill, stroke;
82 | transition-timing-function: cubic-bezier(0.4, 0, 0.2, 1);
83 | transition-duration: 150ms;
84 | }
85 |
86 | .richTextLink:hover {
87 | color: rgb(2 132 199);
88 | }
89 |
90 | @media (min-width: 640px) {
91 | .title {
92 | font-size: 2.25rem;
93 | line-height: 2.5rem;
94 | }
95 | }
96 |
--------------------------------------------------------------------------------
/css/Pokemon.module.css:
--------------------------------------------------------------------------------
1 | .containerNotFound{
2 | text-align: center;
3 | color: rgb(239 68 68);
4 | text-decoration-line: underline;
5 | font-size: 1.25rem; /* 20px */
6 | line-height: 1.75rem; /* 28px */
7 | }
8 |
9 | .container {
10 | max-width: 48rem; /* 768px */
11 | margin-left: auto;
12 | margin-right: auto;
13 | }
14 |
15 | .image{
16 | margin-left: auto;
17 | margin-right: auto;
18 | width: 9rem; /* 144px */
19 | margin-bottom: 1rem; /* 16px */
20 | }
21 |
22 | .title{
23 | font-size: 3rem; /* 48px */
24 | line-height: 1;
25 | font-weight: 800;
26 | text-align: center;
27 | margin-bottom: 1.5rem; /* 24px */
28 | }
--------------------------------------------------------------------------------
/css/errorNoFooter.module.css:
--------------------------------------------------------------------------------
1 | .container {
2 | max-width: 64rem;
3 | margin-left: auto;
4 | margin-right: auto;
5 | padding-left: 1.5rem;
6 | padding-right: 1.5rem;
7 | padding-top: 5rem;
8 | padding-bottom: 5rem;
9 | color: rgb(75 85 99);
10 | }
11 |
12 | .title {
13 | font-size: 1.5rem;
14 | line-height: 2rem;
15 |
16 | color: rgb(248 113 113);
17 | font-weight: 600;
18 | margin-bottom: 2rem;
19 | }
20 |
21 | .paragraph {
22 | margin-bottom: 1.5rem;
23 | }
24 |
--------------------------------------------------------------------------------
/css/errorNoHeader.module.css:
--------------------------------------------------------------------------------
1 | .container {
2 | max-width: 64rem;
3 | margin-left: auto;
4 | margin-right: auto;
5 | padding-left: 1.5rem;
6 | padding-right: 1.5rem;
7 | padding-top: 5rem;
8 | padding-bottom: 5rem;
9 |
10 | color: rgb(75 85 99);
11 | }
12 |
13 | .title {
14 | font-size: 1.5rem;
15 | line-height: 2rem;
16 | color: rgb(248 113 113);
17 | font-weight: 600;
18 | margin-bottom: 2rem;
19 | }
20 |
21 | .paragraph {
22 | margin-bottom: 1.5rem;
23 | }
24 |
--------------------------------------------------------------------------------
/css/errorNoKeys.module.css:
--------------------------------------------------------------------------------
1 | .container {
2 | max-width: 64rem;
3 | margin-left: auto;
4 | margin-right: auto;
5 | padding-left: 1.5rem;
6 | padding-right: 1.5rem;
7 | padding-top: 5rem;
8 | padding-bottom: 5rem;
9 | color: rgb(75 85 99);
10 | }
11 |
12 | .title {
13 | font-size: 1.5rem;
14 | line-height: 2rem;
15 | color: rgb(220 38 38);
16 | font-weight: 600;
17 | margin-bottom: 2rem;
18 | }
19 |
20 | .marginFromTitle {
21 | margin-bottom: 1.5rem;
22 | }
23 |
24 | .codeError {
25 | font-size: 0.875rem;
26 | line-height: 1.25rem;
27 | color: rgb(0 0 0);
28 | background-color: rgb(243 244 246);
29 | padding-left: 0.25rem;
30 | padding-right: 0.25rem;
31 | padding-top: 0.25rem;
32 | padding-bottom: 0.25rem;
33 | border-radius: 0.25rem;
34 | }
35 |
36 | .marginFromCode {
37 | margin-bottom: 0.5rem;
38 | }
39 |
--------------------------------------------------------------------------------
/css/layout.module.css:
--------------------------------------------------------------------------------
1 | .container {
2 | display: flex;
3 | flex-direction: column;
4 | min-height: 100vh;
5 | justify-content: space-between;
6 | -webkit-font-smoothing: antialiased;
7 | -moz-osx-font-smoothing: grayscale;
8 | }
9 |
10 | .childrenContainer {
11 | margin-bottom: auto;
12 | }
13 |
--------------------------------------------------------------------------------
/css/style.css:
--------------------------------------------------------------------------------
1 | *,
2 | ::before,
3 | ::after {
4 | box-sizing: border-box;
5 | /* 1 */
6 | border-width: 0;
7 | /* 2 */
8 | border-style: solid;
9 | /* 2 */
10 | border-color: #e5e7eb;
11 | /* 2 */
12 | }
13 |
14 | html {
15 | line-height: 1.5;
16 | /* 1 */
17 | -webkit-text-size-adjust: 100%;
18 | /* 2 */
19 | -moz-tab-size: 4;
20 | /* 3 */
21 | -o-tab-size: 4;
22 | tab-size: 4;
23 | /* 3 */
24 | }
25 |
26 | body {
27 | margin: 0;
28 | line-height: inherit;
29 | }
30 |
31 | hr {
32 | height: 0;
33 | /* 1 */
34 | color: inherit;
35 | /* 2 */
36 | border-top-width: 1px;
37 | /* 3 */
38 | }
39 |
40 | abbr:where([title]) {
41 | -webkit-text-decoration: underline dotted;
42 | text-decoration: underline dotted;
43 | }
44 |
45 | h1,
46 | h2,
47 | h3,
48 | h4,
49 | h5,
50 | h6 {
51 | font-size: inherit;
52 | font-weight: inherit;
53 | }
54 |
55 | a {
56 | color: inherit;
57 | text-decoration: inherit;
58 | }
59 |
60 | b,
61 | strong {
62 | font-weight: bolder;
63 | }
64 |
65 | code,
66 | kbd,
67 | samp,
68 | pre {
69 | font-family: ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, 'Liberation Mono',
70 | 'Courier New', monospace;
71 | /* 1 */
72 | font-size: 1em;
73 | /* 2 */
74 | }
75 |
76 | small {
77 | font-size: 80%;
78 | }
79 |
80 | sub,
81 | sup {
82 | font-size: 75%;
83 | line-height: 0;
84 | position: relative;
85 | vertical-align: baseline;
86 | }
87 |
88 | sub {
89 | bottom: -0.25em;
90 | }
91 |
92 | sup {
93 | top: -0.5em;
94 | }
95 |
96 | table {
97 | text-indent: 0;
98 | /* 1 */
99 | border-color: inherit;
100 | /* 2 */
101 | border-collapse: collapse;
102 | /* 3 */
103 | }
104 |
105 | button,
106 | input,
107 | optgroup,
108 | select,
109 | textarea {
110 | font-family: inherit;
111 | /* 1 */
112 | font-size: 100%;
113 | /* 1 */
114 | line-height: inherit;
115 | /* 1 */
116 | color: inherit;
117 | /* 1 */
118 | margin: 0;
119 | /* 2 */
120 | padding: 0;
121 | /* 3 */
122 | }
123 |
124 | button,
125 | select {
126 | text-transform: none;
127 | }
128 |
129 | button,
130 | [type='button'],
131 | [type='reset'],
132 | [type='submit'] {
133 | background-image: none;
134 | }
135 |
136 | :-moz-focusring {
137 | outline: auto;
138 | }
139 |
140 | :-moz-ui-invalid {
141 | box-shadow: none;
142 | }
143 |
144 | progress {
145 | vertical-align: baseline;
146 | }
147 |
148 | ::-webkit-inner-spin-button,
149 | ::-webkit-outer-spin-button {
150 | height: auto;
151 | }
152 |
153 | [type='search'] {
154 | /* 1 */
155 | outline-offset: -2px;
156 | /* 2 */
157 | }
158 |
159 | ::-webkit-search-decoration {
160 | -webkit-appearance: none;
161 | }
162 |
163 | ::-webkit-file-upload-button {
164 | -webkit-appearance: button;
165 | /* 1 */
166 | font: inherit;
167 | /* 2 */
168 | }
169 |
170 | summary {
171 | display: list-item;
172 | }
173 |
174 | blockquote,
175 | dl,
176 | dd,
177 | h1,
178 | h2,
179 | h3,
180 | h4,
181 | h5,
182 | h6,
183 | hr,
184 | figure,
185 | p,
186 | pre {
187 | margin: 0;
188 | }
189 |
190 | fieldset {
191 | margin: 0;
192 | padding: 0;
193 | }
194 |
195 | legend {
196 | padding: 0;
197 | }
198 |
199 | ol,
200 | ul,
201 | menu {
202 | list-style: none;
203 | margin: 0;
204 | padding: 0;
205 | }
206 |
207 | textarea {
208 | resize: vertical;
209 | }
210 |
211 | input::-moz-placeholder,
212 | textarea::-moz-placeholder {
213 | opacity: 1;
214 | /* 1 */
215 | color: #9ca3af;
216 | /* 2 */
217 | }
218 |
219 | input:-ms-input-placeholder,
220 | textarea:-ms-input-placeholder {
221 | opacity: 1;
222 | /* 1 */
223 | color: #9ca3af;
224 | /* 2 */
225 | }
226 |
227 | input::placeholder,
228 | textarea::placeholder {
229 | opacity: 1;
230 | /* 1 */
231 | color: #9ca3af;
232 | /* 2 */
233 | }
234 |
235 | button,
236 | [role='button'] {
237 | cursor: pointer;
238 | }
239 |
240 | :disabled {
241 | cursor: default;
242 | }
243 |
244 | img,
245 | svg,
246 | video,
247 | canvas,
248 | audio,
249 | iframe,
250 | embed,
251 | object {
252 | display: block;
253 | }
254 |
255 | /*
256 | Constrain images and videos to the parent width and preserve their intrinsic aspect ratio. (https://github.com/mozdevs/cssremedy/issues/14)
257 | */
258 |
259 | img,
260 | video {
261 | max-width: 100%;
262 | height: auto;
263 | }
264 |
265 | /*
266 | Ensure the default browser behavior of the `hidden` attribute.
267 | */
268 |
269 | [hidden] {
270 | display: none;
271 | }
272 |
273 | .whiteContentClass {
274 | -webkit-font-smoothing: antialiased;
275 | -moz-osx-font-smoothing: grayscale;
276 | background-color: white;
277 | }
278 |
279 | .darkContentClass {
280 | background-color: rgb(17 24 39);
281 | }
282 |
--------------------------------------------------------------------------------
/next-env.d.ts:
--------------------------------------------------------------------------------
1 | ///
2 | ///
3 |
4 | // NOTE: This file should not be edited
5 | // see https://nextjs.org/docs/pages/api-reference/config/typescript for more information.
6 |
--------------------------------------------------------------------------------
/next.config.js:
--------------------------------------------------------------------------------
1 | module.exports = {
2 | i18n: {
3 | locales: ['en'], // Add your languages here
4 | defaultLocale: 'en',
5 | localeDetection: false,
6 | },
7 | }
8 |
--------------------------------------------------------------------------------
/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "nextjs-starter-reactbricks",
3 | "private": true,
4 | "license": "MIT",
5 | "version": "1.3.6",
6 | "author": "Matteo Frana ",
7 | "scripts": {
8 | "dev": "next dev",
9 | "build": "next build",
10 | "start": "next start"
11 | },
12 | "dependencies": {
13 | "classnames": "^2.5.1",
14 | "next": "15.2.2",
15 | "next-themes": "^0.4.6",
16 | "normalize.css": "^8.0.1",
17 | "react": "^19.0.0",
18 | "react-bricks": "^4.7.1",
19 | "react-dom": "^19.0.0",
20 | "react-icons": "^5.5.0"
21 | },
22 | "devDependencies": {
23 | "@types/jsonp": "^0.2.3",
24 | "@types/node": "^22.0.0",
25 | "@types/prismjs": "^1.26.5",
26 | "@types/react": "^19.0.10",
27 | "@types/react-slick": "^0.23.13",
28 | "typescript": "^5.5.4"
29 | }
30 | }
31 |
--------------------------------------------------------------------------------
/pages/[[...slug]].tsx:
--------------------------------------------------------------------------------
1 | import { GetStaticPaths, GetStaticProps } from "next";
2 | import Head from "next/head";
3 | import { ReactNode } from "react";
4 | import {
5 | PageViewer,
6 | cleanPage,
7 | fetchPage,
8 | fetchPages,
9 | renderJsonLd,
10 | renderMeta,
11 | types,
12 | useReactBricksContext,
13 | } from "react-bricks/frontend";
14 | import ErrorNoFooter from "../components/errorNoFooter";
15 | import ErrorNoHeader from "../components/errorNoHeader";
16 | import ErrorNoKeys from "../components/errorNoKeys";
17 | import Layout from "../components/layout";
18 | import config from "../react-bricks/config";
19 |
20 | interface PageProps {
21 | page: types.Page;
22 | header: types.Page;
23 | footer: types.Page;
24 | errorNoKeys: string;
25 | errorPage: boolean;
26 | errorHeader: boolean;
27 | errorFooter: boolean;
28 | }
29 |
30 | const Page: React.FC = ({
31 | page,
32 | header,
33 | footer,
34 | errorNoKeys,
35 | errorPage,
36 | errorHeader,
37 | errorFooter,
38 | }) => {
39 | // Clean the received content
40 | // Removes unknown or not allowed bricks
41 | const { pageTypes, bricks } = useReactBricksContext();
42 | const pageOk = page ? cleanPage(page, pageTypes, bricks) : null;
43 | const headerOk = header ? cleanPage(header, pageTypes, bricks) : null;
44 | const footerOk = footer ? cleanPage(footer, pageTypes, bricks) : null;
45 |
46 | return (
47 |
48 | {pageOk && !errorPage && !errorNoKeys && (
49 | <>
50 |
51 | {renderMeta(pageOk) as ReactNode}
52 | {renderJsonLd(pageOk) as ReactNode}
53 |
54 | {headerOk && !errorHeader ? (
55 |
56 | ) : (
57 |
58 | )}
59 |
60 | {footerOk && !errorFooter ? (
61 |
62 | ) : (
63 |
64 | )}
65 | >
66 | )}
67 | {errorNoKeys && }
68 |
69 | );
70 | };
71 |
72 | export const getStaticProps: GetStaticProps = async (context) => {
73 | let errorNoKeys: boolean = false;
74 |
75 | if (!config.apiKey) {
76 | errorNoKeys = true;
77 | return { props: { errorNoKeys } };
78 | }
79 |
80 | const { slug } = context.params;
81 |
82 | let errorPage: boolean = false;
83 | let errorHeader: boolean = false;
84 | let errorFooter: boolean = false;
85 |
86 | let cleanSlug = "";
87 |
88 | if (!slug) {
89 | cleanSlug = "/";
90 | } else if (typeof slug === "string") {
91 | cleanSlug = slug;
92 | } else {
93 | cleanSlug = slug.join("/");
94 | }
95 |
96 | const [page, header, footer] = await Promise.all([
97 | fetchPage({ slug: cleanSlug, language: context.locale, config }).catch(
98 | () => {
99 | errorPage = true;
100 | return {};
101 | }
102 | ),
103 | fetchPage({ slug: "header", language: context.locale, config }).catch(
104 | () => {
105 | errorHeader = true;
106 | return {};
107 | }
108 | ),
109 | fetchPage({ slug: "footer", language: context.locale, config }).catch(
110 | () => {
111 | errorFooter = true;
112 | return {};
113 | }
114 | ),
115 | ]);
116 |
117 | return {
118 | props: {
119 | page,
120 | header,
121 | footer,
122 | errorNoKeys,
123 | errorPage,
124 | errorHeader,
125 | errorFooter,
126 | },
127 | };
128 | };
129 |
130 | export const getStaticPaths: GetStaticPaths = async (context) => {
131 | if (!config.apiKey) {
132 | return { paths: [], fallback: true };
133 | }
134 | const allPages = await fetchPages(config.apiKey);
135 |
136 | const paths = allPages
137 | .map((page) =>
138 | page.translations
139 | .filter(
140 | (translation) => context.locales.indexOf(translation.language) > -1
141 | )
142 | .map((translation) => ({
143 | params: {
144 | slug: translation.slug === "/" ? [""] : translation.slug.split("/"),
145 | },
146 | locale: translation.language,
147 | }))
148 | )
149 | .flat();
150 |
151 | return { paths, fallback: false };
152 | };
153 |
154 | export default Page;
155 |
--------------------------------------------------------------------------------
/pages/_app.tsx:
--------------------------------------------------------------------------------
1 | import type { AppProps } from "next/app"
2 | import { ThemeProvider } from "next-themes"
3 | import ReactBricksApp from "../components/ReactBricksApp"
4 |
5 | import "../css/style.css"
6 |
7 | const MyApp = (props: AppProps) => {
8 | return (
9 |
11 |
12 |
13 | )
14 | }
15 |
16 | export default MyApp
17 |
--------------------------------------------------------------------------------
/pages/admin/app-settings.tsx:
--------------------------------------------------------------------------------
1 | import React from 'react'
2 | import Head from 'next/head'
3 | import { Admin, AppSettings } from 'react-bricks'
4 |
5 | const AdminAppSettings: React.FC = () => {
6 | return (
7 |
8 |
9 | App Settings
10 |
11 |
12 |
13 | )
14 | }
15 |
16 | export default AdminAppSettings
17 |
--------------------------------------------------------------------------------
/pages/admin/editor.tsx:
--------------------------------------------------------------------------------
1 | import React from 'react'
2 | import Head from 'next/head'
3 | import { Admin, Editor } from 'react-bricks'
4 |
5 | const AdminEditor: React.FC = () => {
6 | return (
7 |
8 |
9 | Editor
10 |
11 |
12 |
13 | )
14 | }
15 |
16 | export default AdminEditor
17 |
--------------------------------------------------------------------------------
/pages/admin/index.tsx:
--------------------------------------------------------------------------------
1 | import React from 'react'
2 | import Head from 'next/head'
3 | import { Admin, Login } from 'react-bricks'
4 |
5 | const AdminLogin: React.FC = () => {
6 | return (
7 |
8 |
9 | Login
10 |
11 |
12 |
13 | )
14 | }
15 |
16 | export default AdminLogin
17 |
--------------------------------------------------------------------------------
/pages/admin/media.tsx:
--------------------------------------------------------------------------------
1 | import React from 'react'
2 | import Head from 'next/head'
3 | import { Admin, MediaLibrary } from 'react-bricks'
4 |
5 | const AdminMediaLibrary: React.FC = () => {
6 | return (
7 |
8 |
9 | Media Library
10 |
11 |
12 |
13 | )
14 | }
15 |
16 | export default AdminMediaLibrary
17 |
--------------------------------------------------------------------------------
/pages/admin/playground.tsx:
--------------------------------------------------------------------------------
1 | import React from 'react'
2 | import Head from 'next/head'
3 | import { Admin, Playground } from 'react-bricks'
4 |
5 | const AdminPlayground: React.FC = () => {
6 | return (
7 |
8 |
9 | Playground
10 |
11 |
12 |
13 | )
14 | }
15 |
16 | export default AdminPlayground
17 |
--------------------------------------------------------------------------------
/pages/admin/sso-failure.tsx:
--------------------------------------------------------------------------------
1 | import React, { useEffect } from 'react'
2 | import { Admin, SsoLoginFailure } from 'react-bricks'
3 |
4 | const AdminSsoFailure: React.FC = () => {
5 | useEffect(() => {
6 | document.title = 'SSO Login Failure'
7 | }, [])
8 |
9 | return (
10 |
11 |
12 |
13 | )
14 | }
15 |
16 | export default AdminSsoFailure
17 |
--------------------------------------------------------------------------------
/pages/admin/sso-login.tsx:
--------------------------------------------------------------------------------
1 | import React, { useEffect } from 'react'
2 | import { Admin, SsoLogin } from 'react-bricks'
3 |
4 | const AdminSSOLogin: React.FC = () => {
5 | useEffect(() => {
6 | document.title = 'SSO Login'
7 | }, [])
8 |
9 | return (
10 |
11 |
12 |
13 | )
14 | }
15 |
16 | export default AdminSSOLogin
17 |
--------------------------------------------------------------------------------
/pages/admin/sso-success.tsx:
--------------------------------------------------------------------------------
1 | import React, { useEffect } from 'react'
2 | import { Admin, SsoLoginSuccess } from 'react-bricks'
3 |
4 | const AdminSsoSuccess: React.FC = () => {
5 | useEffect(() => {
6 | document.title = 'SSO Login Success'
7 | }, [])
8 |
9 | return (
10 |
11 |
12 |
13 | )
14 | }
15 |
16 | export default AdminSsoSuccess
17 |
--------------------------------------------------------------------------------
/pages/preview.tsx:
--------------------------------------------------------------------------------
1 | import React from 'react'
2 | import Head from 'next/head'
3 | import { Preview } from 'react-bricks/frontend'
4 |
5 | const PagePreview: React.FC = () => {
6 | return (
7 | <>
8 |
9 | Preview
10 |
11 |
12 | >
13 | )
14 | }
15 |
16 | export default PagePreview
17 |
--------------------------------------------------------------------------------
/public/favicon.ico:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ReactBricks/nextjs-starter-reactbricks/816bd62738f6b0898ff4c68c37a55db5aff45ff6/public/favicon.ico
--------------------------------------------------------------------------------
/public/logo.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/public/react-bricks-icon.svg:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
81 |
--------------------------------------------------------------------------------
/public/react-bricks-logo.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/react-bricks/NextLink.tsx:
--------------------------------------------------------------------------------
1 | import Link from 'next/link'
2 | import { useRouter } from 'next/router'
3 | import { types } from 'react-bricks/frontend'
4 |
5 | const NextLink: types.RenderLocalLink = ({
6 | href,
7 | target,
8 | rel,
9 | className,
10 | activeClassName,
11 | children,
12 | }) => {
13 | const router = useRouter()
14 |
15 | let anchorClassName = ''
16 |
17 | if (router.asPath === href) {
18 | anchorClassName = `${className} ${activeClassName}`
19 | } else {
20 | anchorClassName = className
21 | }
22 |
23 | return (
24 |
25 | {children}
26 |
27 | )
28 | }
29 |
30 | export default NextLink
31 |
--------------------------------------------------------------------------------
/react-bricks/bricks/HeroUnit.tsx:
--------------------------------------------------------------------------------
1 | import React from 'react'
2 | import { Text, RichText, Image, types } from 'react-bricks/frontend'
3 | import styles from '../../css/HeroUnit.module.css'
4 |
5 | //=============================
6 | // Local Types
7 | //=============================
8 | type Padding = 'big' | 'small'
9 |
10 | interface HeroUnitProps {
11 | padding: Padding
12 | title: string
13 | text: string
14 | }
15 |
16 | //=============================
17 | // Component to be rendered
18 | //=============================
19 | const MyHeroUnit: types.Brick = ({ padding }) => {
20 | return (
21 |
22 |
27 |
28 |
35 |
(
37 | {props.children}
38 | )}
39 | placeholder="Type a title..."
40 | propName="title"
41 | />
42 | (
44 | {props.children}
45 | )}
46 | placeholder="Type a text..."
47 | propName="text"
48 | allowedFeatures={[
49 | types.RichTextFeatures.Bold,
50 | types.RichTextFeatures.Italic,
51 | types.RichTextFeatures.Highlight,
52 | types.RichTextFeatures.Code,
53 | types.RichTextFeatures.Link,
54 | ]}
55 | renderCode={(props) => (
56 | {props.children}
57 | )}
58 | renderLink={(props) => (
59 |
60 | {props.children}
61 |
62 | )}
63 | />
64 |
65 |
66 |
67 | )
68 | }
69 |
70 | //=============================
71 | // Brick Schema
72 | //=============================
73 | MyHeroUnit.schema = {
74 | name: 'my-hero-unit',
75 | label: 'Custom Hero Unit',
76 | getDefaultProps: () => ({
77 | padding: 'big',
78 | title: 'This is a custom Hero Unit',
79 | text: "We are a hi-tech web development company committed to deliver great products on time. We love to understand our customers' needs and exceed expectations.",
80 | }),
81 | sideEditProps: [
82 | {
83 | name: 'padding',
84 | label: 'Padding',
85 | type: types.SideEditPropType.Select,
86 | selectOptions: {
87 | display: types.OptionsDisplay.Select,
88 | options: [
89 | { value: 'big', label: 'Big Padding' },
90 | { value: 'small', label: 'Small Padding' },
91 | ],
92 | },
93 | },
94 | ],
95 | }
96 |
97 | export default MyHeroUnit
98 |
--------------------------------------------------------------------------------
/react-bricks/bricks/features/FeatureItem.tsx:
--------------------------------------------------------------------------------
1 | import * as React from 'react'
2 | import { Image, types, Text, Link, Plain } from 'react-bricks/frontend'
3 | import classNames from 'classnames'
4 | import styles from '../../../css/FeatureItem.module.css'
5 | import { ColsNumber } from './Features'
6 | import { icons } from './defaultImages'
7 |
8 | export interface FeatureItemProps {
9 | colsNumber: ColsNumber
10 | withIcon: boolean
11 | withLink: boolean
12 | linkText: any
13 | linkPath: string
14 | }
15 |
16 | const getColumnClass = (colsNumber: ColsNumber) => {
17 | switch (colsNumber) {
18 | case '2':
19 | return styles.cols2
20 | case '3':
21 | return styles.cols3
22 | case '4':
23 | return styles.cols4
24 | }
25 | }
26 |
27 | const FeatureItem: types.Brick = ({
28 | colsNumber,
29 | withIcon,
30 | withLink,
31 | linkText,
32 | linkPath,
33 | }) => {
34 | const linkTextPlain =
35 | typeof linkText === 'string' ? linkText : Plain.serialize(linkText)
36 |
37 | return (
38 |
44 | {withIcon && (
45 |
{
51 | return {children}
52 | }}
53 | />
54 | )}
55 |
56 |
57 |
(
61 | {props.children}
62 | )}
63 | />
64 | (
68 | {props.children}
69 | )}
70 | />
71 | {withLink && (
72 |
73 |
80 |
81 |
{props.children}
}
83 | placeholder="Link..."
84 | propName="linkText"
85 | />
86 |
87 |
101 |
102 |
103 | )}
104 |
105 |
106 | )
107 | }
108 | FeatureItem.schema = {
109 | name: 'feature-item',
110 | label: 'Feature',
111 | category: 'main content',
112 | hideFromAddMenu: true,
113 | playgroundLinkLabel: 'View source code on Github',
114 | playgroundLinkUrl:
115 | 'https://github.com/ReactBricks/react-bricks-ui/blob/master/src/website/Features/FeatureItem.tsx',
116 |
117 | getDefaultProps: () => ({
118 | title: 'The best experience for editors',
119 | text: 'Your marketing team hates gray forms. Give them the easiest UX.',
120 | withIcon: true,
121 | withLink: false,
122 | image: icons.PHOTO_STACK,
123 | colsNumber: '2',
124 | linkText: '',
125 | linkPath: '',
126 | }),
127 | sideEditProps: [
128 | {
129 | name: 'withIcon',
130 | label: 'With icon',
131 | type: types.SideEditPropType.Boolean,
132 | },
133 | {
134 | name: 'withLink',
135 | label: 'With link',
136 | type: types.SideEditPropType.Boolean,
137 | },
138 | {
139 | name: 'linkPath',
140 | label: 'Link to',
141 | type: types.SideEditPropType.Text,
142 | show: ({ withLink }) => !!withLink,
143 | },
144 | ],
145 | }
146 |
147 | export default FeatureItem
148 |
--------------------------------------------------------------------------------
/react-bricks/bricks/features/Features.tsx:
--------------------------------------------------------------------------------
1 | import * as React from "react"
2 | import { Repeater, types } from "react-bricks/frontend"
3 |
4 | import classNames from "classnames"
5 |
6 | import styles from "../../../css/Features.module.css"
7 |
8 | import { icons } from "./defaultImages"
9 |
10 | export type ColsNumber = "2" | "3" | "4"
11 |
12 | interface FeaturesProps {
13 | colsNumber: ColsNumber
14 | }
15 |
16 | const Features: types.Brick = ({ colsNumber }) => {
17 | return (
18 |
28 | )
29 | }
30 | Features.schema = {
31 | name: "features",
32 | label: "Features",
33 | category: "main content",
34 | tags: ["features"],
35 | playgroundLinkLabel: "View source code on Github",
36 | playgroundLinkUrl:
37 | "https://github.com/ReactBricks/react-bricks-ui/blob/master/src/website/Features/Features.tsx",
38 |
39 | getDefaultProps: () => ({
40 | colsNumber: "2",
41 | features: [
42 | {
43 | title: "The best experience for editors",
44 | text: "Your marketing team hates gray forms. Give them the easiest UX.",
45 | withIcon: true,
46 | withLink: false,
47 | image: icons.PHOTO_STACK,
48 | },
49 | {
50 | title: "React components for devs",
51 | text: "Leverage React to create amazing visually editable content blocks.",
52 | withIcon: true,
53 | withLink: false,
54 | image: icons.MIND_MAP,
55 | },
56 | {
57 | title: "Your design system",
58 | text: "Deploy your pixel-perfect design system and be sure nobody can break it..",
59 | withIcon: true,
60 | withLink: false,
61 | image: icons.RADAR_PLOT,
62 | },
63 | {
64 | title: "Enterprise ready",
65 | text: "Collaboration, localization, granular permissions, SSO, top support: we got you covered.",
66 | withIcon: true,
67 | withLink: false,
68 | image: icons.DATABASE,
69 | },
70 | ],
71 | }),
72 | repeaterItems: [
73 | {
74 | name: "features",
75 | itemType: "feature-item",
76 | itemLabel: "Feature",
77 | min: 0,
78 | max: 9,
79 | },
80 | ],
81 | sideEditProps: [
82 | {
83 | groupName: "Columns",
84 | defaultOpen: true,
85 | props: [
86 | {
87 | name: "colsNumber",
88 | label: "Columns number",
89 | type: types.SideEditPropType.Select,
90 | selectOptions: {
91 | display: types.OptionsDisplay.Radio,
92 | options: [
93 | { value: "2", label: "2 columns" },
94 | { value: "3", label: "3 columns" },
95 | { value: "4", label: "4 columns" },
96 | ],
97 | },
98 | },
99 | ],
100 | },
101 | ],
102 | }
103 | export default Features
104 |
--------------------------------------------------------------------------------
/react-bricks/bricks/features/defaultImages.ts:
--------------------------------------------------------------------------------
1 | import { types } from "react-bricks"
2 |
3 | type Images = Record
4 |
5 | export const customers = {
6 | WOOSMAP: {
7 | src: "https://images.reactbricks.com/original/93ed8ddd-a8cd-40dc-a4dd-d954ea568cad.svg",
8 | placeholderSrc:
9 | "https://images.reactbricks.com/original/93ed8ddd-a8cd-40dc-a4dd-d954ea568cad.svg",
10 | srcSet: "",
11 | alt: "Woosmap",
12 | seoName: "woosmap",
13 | width: 997.334,
14 | height: 198.205,
15 | },
16 | CAPBASE: {
17 | src: "https://images.reactbricks.com/original/6278b20a-e04d-4e0e-b2dd-d8e27228c069.svg",
18 | placeholderSrc:
19 | "https://images.reactbricks.com/original/6278b20a-e04d-4e0e-b2dd-d8e27228c069.svg",
20 | srcSet: "",
21 | alt: "Capbase",
22 | seoName: "capbase",
23 | width: 1000,
24 | height: 300,
25 | },
26 | CASAVO: {
27 | src: "https://images.reactbricks.com/original/b6895334-198a-43d9-aa53-f27b7ff75f53.svg",
28 | placeholderSrc:
29 | "https://images.reactbricks.com/original/b6895334-198a-43d9-aa53-f27b7ff75f53.svg",
30 | srcSet: "",
31 | alt: "Casavo",
32 | seoName: "casavo",
33 | width: 520.76,
34 | height: 135.83,
35 | },
36 | EVERFUND: {
37 | src: "https://images.reactbricks.com/original/9124b82c-686e-4de5-bd14-291d2fce37b8.svg",
38 | placeholderSrc:
39 | "https://images.reactbricks.com/original/9124b82c-686e-4de5-bd14-291d2fce37b8.svg",
40 | srcSet: "",
41 | alt: "Everfund",
42 | seoName: "everfund",
43 | width: 2698.39,
44 | height: 585.2,
45 | },
46 | NEOSKOP: {
47 | src: "https://images.reactbricks.com/original/e39a61c5-0a25-49bd-9f77-3d29fb43e5af.svg",
48 | placeholderSrc:
49 | "https://images.reactbricks.com/original/e39a61c5-0a25-49bd-9f77-3d29fb43e5af.svg",
50 | srcSet: "",
51 | alt: "Neoskop",
52 | seoName: "neoskop",
53 | width: 145,
54 | height: 40,
55 | },
56 | } as const satisfies Images
57 |
58 | export const logos = {
59 | REACT: {
60 | src: "https://images.reactbricks.com/original/5a717763-afd5-4ec5-8a68-12a0d6e4fd08.svg",
61 | placeholderSrc:
62 | "https://images.reactbricks.com/original/5a717763-afd5-4ec5-8a68-12a0d6e4fd08.svg",
63 | srcSet: "",
64 | alt: "React",
65 | seoName: "react",
66 | width: 120,
67 | height: 60,
68 | },
69 | VUE: {
70 | src: "https://images.reactbricks.com/original/272fad93-049f-4cd7-bdd9-4ed823ba2599.svg",
71 | placeholderSrc:
72 | "https://images.reactbricks.com/original/272fad93-049f-4cd7-bdd9-4ed823ba2599.svg",
73 | srcSet: "",
74 | alt: "Vue",
75 | seoName: "vue",
76 | width: 120,
77 | height: 60,
78 | },
79 | SVELTE: {
80 | src: "https://images.reactbricks.com/original/44c7c7db-06f9-4e33-b017-1b32a397b96b.svg",
81 | placeholderSrc:
82 | "https://images.reactbricks.com/original/44c7c7db-06f9-4e33-b017-1b32a397b96b.svg",
83 | srcSet: "",
84 | alt: "Svelte",
85 | seoName: "svelte",
86 | width: 800,
87 | height: 800,
88 | },
89 | SOLID: {
90 | src: "https://images.reactbricks.com/original/99a92b01-c9a6-482b-8ed6-aefb20687754.svg",
91 | placeholderSrc:
92 | "https://images.reactbricks.com/original/99a92b01-c9a6-482b-8ed6-aefb20687754.svg",
93 | srcSet: "",
94 | alt: "Solidjs",
95 | seoName: "solidjs",
96 | width: 382.23,
97 | height: 70.7,
98 | },
99 | ASTRO: {
100 | src: "https://images.reactbricks.com/original/faba4d56-5733-432c-a38d-25d701ea7dcf.svg",
101 | placeholderSrc:
102 | "https://images.reactbricks.com/original/faba4d56-5733-432c-a38d-25d701ea7dcf.svg",
103 | srcSet: "",
104 | alt: "Astro",
105 | seoName: "astro-build",
106 | width: 2712,
107 | height: 894,
108 | },
109 | REACT_BRICKS: {
110 | src: "https://images.reactbricks.com/original/7fd7ef1a-928f-45d6-b7a7-ff34bf91c15e.svg",
111 | placeholderSrc:
112 | "https://images.reactbricks.com/original/7fd7ef1a-928f-45d6-b7a7-ff34bf91c15e.svg",
113 | srcSet: "",
114 | alt: "React Bricks",
115 | seoName: "react-bricks",
116 | width: 1700.787,
117 | height: 377.953,
118 | },
119 | } as const satisfies Images
120 |
121 | export const iconLogos = {
122 | REACT: {
123 | src: "https://images.reactbricks.com/original/6a840f50-48f3-45e4-9946-18586c039b2a.svg",
124 | placeholderSrc:
125 | "https://images.reactbricks.com/original/6a840f50-48f3-45e4-9946-18586c039b2a.svg",
126 | srcSet: "",
127 | alt: "React",
128 | seoName: "react",
129 | width: 23,
130 | height: 20.46348,
131 | },
132 | VUE: {
133 | src: "https://images.reactbricks.com/original/ce61fb1d-bc1d-4619-91ad-f01e3981521f.svg",
134 | placeholderSrc:
135 | "https://images.reactbricks.com/original/ce61fb1d-bc1d-4619-91ad-f01e3981521f.svg",
136 | srcSet: "",
137 | alt: "Vue",
138 | seoName: "vue",
139 | width: 261.76,
140 | height: 226.69,
141 | },
142 | SVELTE: {
143 | src: "https://images.reactbricks.com/original/d6598c2b-1093-4fbd-9a1d-5a89af2cde26.svg",
144 | placeholderSrc:
145 | "https://images.reactbricks.com/original/d6598c2b-1093-4fbd-9a1d-5a89af2cde26.svg",
146 | srcSet: "",
147 | alt: "Svelte",
148 | seoName: "svelte",
149 | width: 98.1,
150 | height: 118,
151 | },
152 | SOLID: {
153 | src: "https://images.reactbricks.com/original/2f0e0ce5-a679-42de-9979-3e870540dd49.svg",
154 | placeholderSrc:
155 | "https://images.reactbricks.com/original/2f0e0ce5-a679-42de-9979-3e870540dd49.svg",
156 | srcSet: "",
157 | alt: "Solidjs",
158 | seoName: "solidjs",
159 | width: 166,
160 | height: 155.3,
161 | },
162 | ASTRO: {
163 | src: "https://images.reactbricks.com/original/b51d2e41-02b9-4a5f-acab-68498c22b384.svg",
164 | placeholderSrc:
165 | "https://images.reactbricks.com/original/b51d2e41-02b9-4a5f-acab-68498c22b384.svg",
166 | srcSet: "",
167 | alt: "Astro",
168 | seoName: "astro-build",
169 | width: 1280,
170 | height: 1280,
171 | },
172 | REACT_BRICKS: {
173 | src: "https://images.reactbricks.com/original/0502a7bd-0319-4300-b1df-89876e82c965.svg",
174 | placeholderSrc:
175 | "https://images.reactbricks.com/original/0502a7bd-0319-4300-b1df-89876e82c965.svg",
176 | srcSet: "",
177 | alt: "React Bricks",
178 | seoName: "react-bricks",
179 | width: 980,
180 | height: 979.97,
181 | },
182 | } as const satisfies Images
183 |
184 | export const avatars = {
185 | MATTEO_FRANA: {
186 | src: "https://images.reactbricks.com/original/910d4267-6e46-4d9e-8790-53348ede99fb.svg",
187 | placeholderSrc:
188 | "https://images.reactbricks.com/original/910d4267-6e46-4d9e-8790-53348ede99fb.svg",
189 | srcSet: "",
190 | alt: "Matteo Frana",
191 | seoName: "matteo-frana",
192 | },
193 | STEFAN_NAGEY: {
194 | src: "https://images.reactbricks.com/original/16068142-973d-49e7-b1a2-264c16bd5c34.webp",
195 | placeholderSrc:
196 | "https://images.reactbricks.com/placeholder/16068142-973d-49e7-b1a2-264c16bd5c34.jpg",
197 | srcSet:
198 | "https://images.reactbricks.com/src_set/16068142-973d-49e7-b1a2-264c16bd5c34-100.webp 100w",
199 | alt: "Stefan Nagey",
200 | seoName: "stefan-nagey",
201 | fallbackSrc:
202 | "https://images.reactbricks.com/original/16068142-973d-49e7-b1a2-264c16bd5c34.png",
203 | fallbackSrcSet:
204 | "https://images.reactbricks.com/src_set/16068142-973d-49e7-b1a2-264c16bd5c34-100.png 100w",
205 | fallbackType: "image/jpeg",
206 | width: 100,
207 | height: 100,
208 | },
209 | LAURIE_VOSS: {
210 | src: "https://images.reactbricks.com/original/1f56e3f7-e1cf-4bfa-82d4-6a1a7415b954.webp",
211 | placeholderSrc:
212 | "https://images.reactbricks.com/placeholder/1f56e3f7-e1cf-4bfa-82d4-6a1a7415b954.jpg",
213 | srcSet:
214 | "https://images.reactbricks.com/src_set/1f56e3f7-e1cf-4bfa-82d4-6a1a7415b954-96.webp 96w",
215 | alt: "Laurie Voss",
216 | seoName: "laurie-voss",
217 | fallbackSrc:
218 | "https://images.reactbricks.com/original/1f56e3f7-e1cf-4bfa-82d4-6a1a7415b954.jpg",
219 | fallbackSrcSet:
220 | "https://images.reactbricks.com/src_set/1f56e3f7-e1cf-4bfa-82d4-6a1a7415b954-96.jpg 96w",
221 | fallbackType: "image/jpeg",
222 | width: 96,
223 | height: 96,
224 | },
225 | MAIK_JABLONSKI: {
226 | src: "https://images.reactbricks.com/original/44e9d50a-95a1-4573-aafc-84a94496e319.webp",
227 | placeholderSrc:
228 | "https://images.reactbricks.com/placeholder/44e9d50a-95a1-4573-aafc-84a94496e319.jpg",
229 | srcSet:
230 | "https://images.reactbricks.com/src_set/44e9d50a-95a1-4573-aafc-84a94496e319-450.webp 450w,\nhttps://images.reactbricks.com/src_set/44e9d50a-95a1-4573-aafc-84a94496e319-400.webp 400w,\nhttps://images.reactbricks.com/src_set/44e9d50a-95a1-4573-aafc-84a94496e319-200.webp 200w",
231 | alt: "Maik Jablonski",
232 | seoName: "maik-jablonski",
233 | fallbackSrc:
234 | "https://images.reactbricks.com/original/44e9d50a-95a1-4573-aafc-84a94496e319.jpg",
235 | fallbackSrcSet:
236 | "https://images.reactbricks.com/src_set/44e9d50a-95a1-4573-aafc-84a94496e319-450.jpg 450w,\nhttps://images.reactbricks.com/src_set/44e9d50a-95a1-4573-aafc-84a94496e319-400.jpg 400w,\nhttps://images.reactbricks.com/src_set/44e9d50a-95a1-4573-aafc-84a94496e319-200.jpg 200w",
237 | fallbackType: "image/jpeg",
238 | width: 450,
239 | height: 450,
240 | },
241 | PLACEHOLDER1: {
242 | src: "https://images.reactbricks.com/original/cc2a047d-15f7-47d2-af8f-d4c3a394ca41.svg",
243 | placeholderSrc:
244 | "https://images.reactbricks.com/original/cc2a047d-15f7-47d2-af8f-d4c3a394ca41.svg",
245 | srcSet: "",
246 | alt: "Place Holder",
247 | seoName: "placeholder",
248 | width: 1249.24,
249 | height: 1249.24,
250 | },
251 | AVATAR_MALE: {
252 | src: "https://images.reactbricks.com/original/2f84867e-3c4b-46b6-b64f-6c2f81b5232f.svg",
253 | placeholderSrc:
254 | "https://images.reactbricks.com/original/2f84867e-3c4b-46b6-b64f-6c2f81b5232f.svg",
255 | srcSet: "",
256 | alt: "Alvin",
257 | seoName: "alvin",
258 | width: 102.45,
259 | height: 102.45,
260 | },
261 | AVATAR_FEMALE: {
262 | src: "https://images.reactbricks.com/original/24b26149-514a-40c4-9029-0dfaa22cbe3c.svg",
263 | placeholderSrc:
264 | "https://images.reactbricks.com/original/24b26149-514a-40c4-9029-0dfaa22cbe3c.svg",
265 | srcSet: "",
266 | alt: "Catherine",
267 | seoName: "catherine",
268 | width: 102.45,
269 | height: 102.45,
270 | },
271 | } as const satisfies Images
272 |
273 | export const icons = {
274 | PHOTOS: {
275 | src: "https://images.reactbricks.com/original/21ee754a-8c3d-427a-bc44-8816c05299ae.svg",
276 | placeholderSrc:
277 | "https://images.reactbricks.com/original/21ee754a-8c3d-427a-bc44-8816c05299ae.svg",
278 | srcSet: "",
279 | alt: "Great for content creators and developers",
280 | seoName: "content-creators-ux-cms",
281 | width: 48,
282 | height: 48,
283 | },
284 | TWITTER: {
285 | src: "https://images.reactbricks.com/original/3a2856d6-c209-4c90-9483-85d9959999e2.svg",
286 | placeholderSrc:
287 | "https://images.reactbricks.com/original/3a2856d6-c209-4c90-9483-85d9959999e2.svg",
288 | srcSet: "",
289 | width: 248,
290 | height: 204,
291 | alt: "Twitter icon",
292 | seoName: "twitter-icon",
293 | },
294 | YOUTUBE: {
295 | src: "https://images.reactbricks.com/original/02fb7799-0da2-4537-a6c7-4822bc1410a2.svg",
296 | placeholderSrc:
297 | "https://images.reactbricks.com/original/02fb7799-0da2-4537-a6c7-4822bc1410a2.svg",
298 | srcSet: "",
299 | width: 159,
300 | height: 110,
301 | alt: "Youtube icon",
302 | seoName: "youtube-icon",
303 | },
304 | PHOTO_STACK: {
305 | src: "https://images.reactbricks.com/original/aca3dbf3-ccb6-47cf-973e-059e85e55571.svg",
306 | placeholderSrc:
307 | "https://images.reactbricks.com/original/aca3dbf3-ccb6-47cf-973e-059e85e55571.svg",
308 | srcSet: "",
309 | width: 1,
310 | height: 1,
311 | alt: "Best UX for editors",
312 | seoName: "best-ux-editors",
313 | },
314 | DATABASE: {
315 | src: "https://images.reactbricks.com/original/0037d5f4-d486-4cdf-a64c-dcbf0260ebb3.svg",
316 | placeholderSrc:
317 | "https://images.reactbricks.com/original/0037d5f4-d486-4cdf-a64c-dcbf0260ebb3.svg",
318 | srcSet: "",
319 | width: 1,
320 | height: 1,
321 | alt: "Enterprise-ready",
322 | seoName: "enterprise-ready",
323 | },
324 | MIND_MAP: {
325 | src: "https://images.reactbricks.com/original/dd14c0fe-3f21-4fc1-8362-22e005e82897.svg",
326 | placeholderSrc:
327 | "https://images.reactbricks.com/original/dd14c0fe-3f21-4fc1-8362-22e005e82897.svg",
328 | srcSet: "",
329 | width: 1,
330 | height: 1,
331 | alt: "React components",
332 | seoName: "react-components",
333 | },
334 | RADAR_PLOT: {
335 | src: "https://images.reactbricks.com/original/6f0a3910-b542-4791-a2ab-57474b9b2bb1.svg",
336 | placeholderSrc:
337 | "https://images.reactbricks.com/original/6f0a3910-b542-4791-a2ab-57474b9b2bb1.svg",
338 | srcSet: "",
339 | width: 1,
340 | height: 1,
341 | alt: "Design system",
342 | seoName: "design-system",
343 | },
344 | VISUAL_EDITING: {
345 | src: "https://images.reactbricks.com/original/50313730-79c9-4d6a-b7e0-d8aeb2a936e2.svg",
346 | placeholderSrc:
347 | "https://images.reactbricks.com/original/50313730-79c9-4d6a-b7e0-d8aeb2a936e2.svg",
348 | srcSet: "",
349 | width: 48,
350 | height: 48,
351 | alt: "Best UX for editors",
352 | seoName: "best-ux-editors",
353 | },
354 | COMPONENTS: {
355 | src: "https://images.reactbricks.com/original/cca08a7b-c3ad-4928-a69b-84b5d9e06ef4.svg",
356 | placeholderSrc:
357 | "https://images.reactbricks.com/original/cca08a7b-c3ad-4928-a69b-84b5d9e06ef4.svg",
358 | srcSet: "",
359 | width: 48,
360 | height: 48,
361 | alt: "React components",
362 | seoName: "react-components",
363 | },
364 | MULTILANGUAGE: {
365 | src: "https://images.reactbricks.com/original/643f6d1e-2c4f-40bd-8478-82b43694054b.svg",
366 | placeholderSrc:
367 | "https://images.reactbricks.com/original/643f6d1e-2c4f-40bd-8478-82b43694054b.svg",
368 | srcSet: "",
369 | width: 48,
370 | height: 48,
371 | alt: "",
372 | seoName: "",
373 | },
374 | SCHEDULED_PUBLISHING: {
375 | src: "https://images.reactbricks.com/original/3eaa0b6b-bcf0-4430-b099-3c4f872a6d91.svg",
376 | placeholderSrc:
377 | "https://images.reactbricks.com/original/3eaa0b6b-bcf0-4430-b099-3c4f872a6d91.svg",
378 | srcSet: "",
379 | width: 48,
380 | height: 48,
381 | alt: "Enterprise-ready",
382 | seoName: "enterprise-ready",
383 | },
384 | } as const satisfies Images
385 |
386 | export const photos = {
387 | DESK_MAC: {
388 | src: "https://images.reactbricks.com/original/91a94bb2-7916-4254-9c60-af8d69701dfc.webp",
389 | placeholderSrc:
390 | "https://images.reactbricks.com/placeholder/91a94bb2-7916-4254-9c60-af8d69701dfc.jpg",
391 | srcSet:
392 | "https://images.reactbricks.com/src_set/91a94bb2-7916-4254-9c60-af8d69701dfc-1080.webp 1080w,\nhttps://images.reactbricks.com/src_set/91a94bb2-7916-4254-9c60-af8d69701dfc-800.webp 800w,\nhttps://images.reactbricks.com/src_set/91a94bb2-7916-4254-9c60-af8d69701dfc-400.webp 400w,\nhttps://images.reactbricks.com/src_set/91a94bb2-7916-4254-9c60-af8d69701dfc-200.webp 200w",
393 | alt: "person writing on white paper",
394 | seoName: "dashboard",
395 | fallbackSrc:
396 | "https://images.reactbricks.com/original/91a94bb2-7916-4254-9c60-af8d69701dfc.jpg",
397 | fallbackSrcSet:
398 | "https://images.reactbricks.com/src_set/91a94bb2-7916-4254-9c60-af8d69701dfc-1080.jpg 1080w,\nhttps://images.reactbricks.com/src_set/91a94bb2-7916-4254-9c60-af8d69701dfc-800.jpg 800w,\nhttps://images.reactbricks.com/src_set/91a94bb2-7916-4254-9c60-af8d69701dfc-400.jpg 400w,\nhttps://images.reactbricks.com/src_set/91a94bb2-7916-4254-9c60-af8d69701dfc-200.jpg 200w",
399 | fallbackType: "image/jpeg",
400 | width: 1080,
401 | height: 717,
402 | },
403 | IMAGE_TEXT_STORY_HERO: {
404 | src: "https://images.reactbricks.com/original/1a8b35b7-4793-4c72-836b-86a491718494.webp",
405 | placeholderSrc:
406 | "https://images.reactbricks.com/placeholder/1a8b35b7-4793-4c72-836b-86a491718494.jpg",
407 | srcSet:
408 | "https://images.reactbricks.com/src_set/1a8b35b7-4793-4c72-836b-86a491718494-1080.webp 1080w,\nhttps://images.reactbricks.com/src_set/1a8b35b7-4793-4c72-836b-86a491718494-800.webp 800w,\nhttps://images.reactbricks.com/src_set/1a8b35b7-4793-4c72-836b-86a491718494-400.webp 400w,\nhttps://images.reactbricks.com/src_set/1a8b35b7-4793-4c72-836b-86a491718494-200.webp 200w",
409 | alt: "macbook pro displaying computer icons",
410 | seoName: "dashboard",
411 | fallbackSrc:
412 | "https://images.reactbricks.com/original/1a8b35b7-4793-4c72-836b-86a491718494macbook pro displaying computer icons",
413 | fallbackSrcSet:
414 | "https://images.reactbricks.com/src_set/1a8b35b7-4793-4c72-836b-86a491718494-1080macbook pro displaying computer icons 1080w,\nhttps://images.reactbricks.com/src_set/1a8b35b7-4793-4c72-836b-86a491718494-800macbook pro displaying computer icons 800w,\nhttps://images.reactbricks.com/src_set/1a8b35b7-4793-4c72-836b-86a491718494-400macbook pro displaying computer icons 400w,\nhttps://images.reactbricks.com/src_set/1a8b35b7-4793-4c72-836b-86a491718494-200macbook pro displaying computer icons 200w",
415 | fallbackType: "image/jpeg",
416 | width: 1080,
417 | height: 608,
418 | },
419 | SEASIDE: {
420 | fallbackSrc:
421 | "https://images.reactbricks.com/original/71fd29e5-d54d-4c99-a2da-681bd8d888d1.jpg",
422 | fallbackSrcSet:
423 | "https://images.reactbricks.com/src_set/71fd29e5-d54d-4c99-a2da-681bd8d888d1-1080.jpg 1080w,\nhttps://images.reactbricks.com/src_set/71fd29e5-d54d-4c99-a2da-681bd8d888d1-600.jpg 600w,\nhttps://images.reactbricks.com/src_set/71fd29e5-d54d-4c99-a2da-681bd8d888d1-300.jpg 300w",
424 | fallbackType: "image/jpeg",
425 | src: "https://images.reactbricks.com/original/71fd29e5-d54d-4c99-a2da-681bd8d888d1.webp",
426 | placeholderSrc:
427 | "https://images.reactbricks.com/placeholder/71fd29e5-d54d-4c99-a2da-681bd8d888d1.jpg",
428 | srcSet:
429 | "https://images.reactbricks.com/src_set/71fd29e5-d54d-4c99-a2da-681bd8d888d1-1080.webp 1080w,\nhttps://images.reactbricks.com/src_set/71fd29e5-d54d-4c99-a2da-681bd8d888d1-600.webp 600w,\nhttps://images.reactbricks.com/src_set/71fd29e5-d54d-4c99-a2da-681bd8d888d1-300.webp 300w",
430 | width: 1080,
431 | height: 606,
432 | alt: "aerial photography of islands during daytime",
433 | seoName: "seaside",
434 | },
435 | CAROUSEL_MOUNTAINS_1: {
436 | src: "https://images.reactbricks.com/original/b83f614b-8dc9-4a20-b39f-a7e90374d4cc.webp",
437 | placeholderSrc:
438 | "https://images.reactbricks.com/placeholder/b83f614b-8dc9-4a20-b39f-a7e90374d4cc.jpg",
439 | srcSet:
440 | "https://images.reactbricks.com/src_set/b83f614b-8dc9-4a20-b39f-a7e90374d4cc-1080.webp 1080w,\nhttps://images.reactbricks.com/src_set/b83f614b-8dc9-4a20-b39f-a7e90374d4cc-600.webp 600w,\nhttps://images.reactbricks.com/src_set/b83f614b-8dc9-4a20-b39f-a7e90374d4cc-300.webp 300w",
441 | width: 1080,
442 | height: 270,
443 | alt: "aerial photography of mountain range covered with snow under white and blue sky at daytime",
444 | seoName: "mountains",
445 | fallbackSrc:
446 | "https://images.reactbricks.com/original/b83f614b-8dc9-4a20-b39f-a7e90374d4cc.jpg",
447 | fallbackSrcSet:
448 | "https://images.reactbricks.com/src_set/b83f614b-8dc9-4a20-b39f-a7e90374d4cc-1080.jpg 1080w,\nhttps://images.reactbricks.com/src_set/b83f614b-8dc9-4a20-b39f-a7e90374d4cc-600.jpg 600w,\nhttps://images.reactbricks.com/src_set/b83f614b-8dc9-4a20-b39f-a7e90374d4cc-300.jpg 300w",
449 | fallbackType: "image/jpeg",
450 | },
451 | CAROUSEL_MOUNTAINS_2: {
452 | src: "https://images.reactbricks.com/original/79c16949-6349-45de-996b-5a11b31800e6.webp",
453 | placeholderSrc:
454 | "https://images.reactbricks.com/placeholder/79c16949-6349-45de-996b-5a11b31800e6.jpg",
455 | srcSet:
456 | "https://images.reactbricks.com/src_set/79c16949-6349-45de-996b-5a11b31800e6-1080.webp 1080w,\nhttps://images.reactbricks.com/src_set/79c16949-6349-45de-996b-5a11b31800e6-600.webp 600w,\nhttps://images.reactbricks.com/src_set/79c16949-6349-45de-996b-5a11b31800e6-300.webp 300w",
457 | width: 1080,
458 | height: 270,
459 | alt: "snow mountain under stars",
460 | seoName: "mountains",
461 | fallbackSrc:
462 | "https://images.reactbricks.com/original/79c16949-6349-45de-996b-5a11b31800e6.jpg",
463 | fallbackSrcSet:
464 | "https://images.reactbricks.com/src_set/79c16949-6349-45de-996b-5a11b31800e6-1080.jpg 1080w,\nhttps://images.reactbricks.com/src_set/79c16949-6349-45de-996b-5a11b31800e6-600.jpg 600w,\nhttps://images.reactbricks.com/src_set/79c16949-6349-45de-996b-5a11b31800e6-300.jpg 300w",
465 | fallbackType: "image/jpeg",
466 | },
467 | CAROUSEL_SEA_1: {
468 | src: "https://images.reactbricks.com/original/ae2eea74-6e50-42cd-8dbe-9d17774a1643.webp",
469 | placeholderSrc:
470 | "https://images.reactbricks.com/placeholder/ae2eea74-6e50-42cd-8dbe-9d17774a1643.jpg",
471 | srcSet:
472 | "https://images.reactbricks.com/src_set/ae2eea74-6e50-42cd-8dbe-9d17774a1643-720.webp 720w,\nhttps://images.reactbricks.com/src_set/ae2eea74-6e50-42cd-8dbe-9d17774a1643-600.webp 600w,\nhttps://images.reactbricks.com/src_set/ae2eea74-6e50-42cd-8dbe-9d17774a1643-300.webp 300w",
473 | width: 720,
474 | height: 720,
475 | alt: "boat on seashore",
476 | seoName: "seaside",
477 | fallbackSrc:
478 | "https://images.reactbricks.com/original/ae2eea74-6e50-42cd-8dbe-9d17774a1643.jpg",
479 | fallbackSrcSet:
480 | "https://images.reactbricks.com/src_set/ae2eea74-6e50-42cd-8dbe-9d17774a1643-720.jpg 720w,\nhttps://images.reactbricks.com/src_set/ae2eea74-6e50-42cd-8dbe-9d17774a1643-600.jpg 600w,\nhttps://images.reactbricks.com/src_set/ae2eea74-6e50-42cd-8dbe-9d17774a1643-300.jpg 300w",
481 | fallbackType: "image/jpeg",
482 | },
483 | CAROUSEL_SEA_2: {
484 | src: "https://images.reactbricks.com/original/807fd735-89a6-4f30-b2fe-6eaba36e3319.webp",
485 | placeholderSrc:
486 | "https://images.reactbricks.com/placeholder/807fd735-89a6-4f30-b2fe-6eaba36e3319.jpg",
487 | srcSet:
488 | "https://images.reactbricks.com/src_set/807fd735-89a6-4f30-b2fe-6eaba36e3319-1080.webp 1080w,\nhttps://images.reactbricks.com/src_set/807fd735-89a6-4f30-b2fe-6eaba36e3319-600.webp 600w,\nhttps://images.reactbricks.com/src_set/807fd735-89a6-4f30-b2fe-6eaba36e3319-300.webp 300w",
489 | width: 1080,
490 | height: 1080,
491 | alt: "empty seashore",
492 | seoName: "sea",
493 | fallbackSrc:
494 | "https://images.reactbricks.com/original/807fd735-89a6-4f30-b2fe-6eaba36e3319.jpg",
495 | fallbackSrcSet:
496 | "https://images.reactbricks.com/src_set/807fd735-89a6-4f30-b2fe-6eaba36e3319-1080.jpg 1080w,\nhttps://images.reactbricks.com/src_set/807fd735-89a6-4f30-b2fe-6eaba36e3319-600.jpg 600w,\nhttps://images.reactbricks.com/src_set/807fd735-89a6-4f30-b2fe-6eaba36e3319-300.jpg 300w",
497 | fallbackType: "image/jpeg",
498 | },
499 | CAROUSEL_SEA_3: {
500 | src: "https://images.reactbricks.com/original/a30ad110-b981-4aea-bdd4-8bd27319d319.webp",
501 | placeholderSrc:
502 | "https://images.reactbricks.com/placeholder/a30ad110-b981-4aea-bdd4-8bd27319d319.jpg",
503 | srcSet:
504 | "https://images.reactbricks.com/src_set/a30ad110-b981-4aea-bdd4-8bd27319d319-1080.webp 1080w,\nhttps://images.reactbricks.com/src_set/a30ad110-b981-4aea-bdd4-8bd27319d319-600.webp 600w,\nhttps://images.reactbricks.com/src_set/a30ad110-b981-4aea-bdd4-8bd27319d319-300.webp 300w",
505 | width: 1080,
506 | height: 1080,
507 | alt: "aerial photography of large body of water and shoreline",
508 | seoName: "sea",
509 | fallbackSrc:
510 | "https://images.reactbricks.com/original/a30ad110-b981-4aea-bdd4-8bd27319d319.jpg",
511 | fallbackSrcSet:
512 | "https://images.reactbricks.com/src_set/a30ad110-b981-4aea-bdd4-8bd27319d319-1080.jpg 1080w,\nhttps://images.reactbricks.com/src_set/a30ad110-b981-4aea-bdd4-8bd27319d319-600.jpg 600w,\nhttps://images.reactbricks.com/src_set/a30ad110-b981-4aea-bdd4-8bd27319d319-300.jpg 300w",
513 | fallbackType: "image/jpeg",
514 | },
515 | CAROUSEL_SEA_4: {
516 | src: "https://images.reactbricks.com/original/b87f99ed-7b67-467c-a747-7327546a0fee.webp",
517 | placeholderSrc:
518 | "https://images.reactbricks.com/placeholder/b87f99ed-7b67-467c-a747-7327546a0fee.jpg",
519 | srcSet:
520 | "https://images.reactbricks.com/src_set/b87f99ed-7b67-467c-a747-7327546a0fee-1080.webp 1080w,\nhttps://images.reactbricks.com/src_set/b87f99ed-7b67-467c-a747-7327546a0fee-600.webp 600w,\nhttps://images.reactbricks.com/src_set/b87f99ed-7b67-467c-a747-7327546a0fee-300.webp 300w",
521 | width: 1080,
522 | height: 1080,
523 | alt: "crystal clear water near coconut trees under the sun",
524 | seoName: "sea",
525 | fallbackSrc:
526 | "https://images.reactbricks.com/original/b87f99ed-7b67-467c-a747-7327546a0fee.jpg",
527 | fallbackSrcSet:
528 | "https://images.reactbricks.com/src_set/b87f99ed-7b67-467c-a747-7327546a0fee-1080.jpg 1080w,\nhttps://images.reactbricks.com/src_set/b87f99ed-7b67-467c-a747-7327546a0fee-600.jpg 600w,\nhttps://images.reactbricks.com/src_set/b87f99ed-7b67-467c-a747-7327546a0fee-300.jpg 300w",
529 | fallbackType: "image/jpeg",
530 | },
531 | } as const satisfies Images
532 |
--------------------------------------------------------------------------------
/react-bricks/bricks/features/index.ts:
--------------------------------------------------------------------------------
1 | import { types } from "react-bricks/frontend"
2 | import Features from "./Features"
3 | import FeatureItem from "./FeatureItem"
4 |
5 | const layout: types.Brick[] = [Features, FeatureItem]
6 |
7 | export default layout
8 |
--------------------------------------------------------------------------------
/react-bricks/bricks/index.ts:
--------------------------------------------------------------------------------
1 | import { types } from "react-bricks/frontend"
2 | import layout from "./layout"
3 | import HeroUnit from "./HeroUnit"
4 | import features from "./features"
5 |
6 | const bricks: types.Brick[] = [HeroUnit, ...layout, ...features]
7 |
8 | export default bricks
9 |
--------------------------------------------------------------------------------
/react-bricks/bricks/layout/Button.tsx:
--------------------------------------------------------------------------------
1 | import * as React from 'react'
2 | import classNames from 'classnames'
3 | import { Text, Link, types, useAdminContext } from 'react-bricks/frontend'
4 |
5 | import styles from '../../../css/Button.module.css'
6 |
7 | export interface ButtonProps {
8 | type: 'button' | 'link'
9 | text: string
10 | href: string
11 | isTargetBlank: boolean
12 | buttonType: 'submit' | 'button' | 'reset'
13 | simpleAnchorLink: boolean
14 | variant: 'solid' | 'outline'
15 | padding: 'normal' | 'small'
16 | className?: string
17 | }
18 |
19 | const Button: types.Brick = ({
20 | type,
21 | href,
22 | isTargetBlank,
23 | buttonType,
24 | simpleAnchorLink = false,
25 | variant,
26 | padding,
27 | className,
28 | }) => {
29 | const target = isTargetBlank
30 | ? { target: '_blank', rel: 'noopener noreferrer' }
31 | : {}
32 |
33 | if (type === 'link') {
34 | return (
35 |
49 | {children}}
53 | />
54 |
55 | )
56 | }
57 |
58 | // Button
59 | const { isAdmin, previewMode } = useAdminContext()
60 |
61 | return (
62 |
81 | )
82 | }
83 |
84 | Button.schema = {
85 | name: 'button',
86 | label: 'Button',
87 | category: 'shared',
88 | hideFromAddMenu: true,
89 | playgroundLinkLabel: 'View source code on Github',
90 | playgroundLinkUrl:
91 | 'https://github.com/ReactBricks/react-bricks-ui/blob/master/src/website/shared/Button.tsx',
92 |
93 | getDefaultProps: () => ({
94 | type: 'link',
95 | text: 'Click me',
96 | href: '',
97 | isTargetBlank: false,
98 | buttonType: 'submit',
99 | simpleAnchorLink: false,
100 | variant: 'solid',
101 | padding: 'normal',
102 | }),
103 | sideEditProps: [
104 | {
105 | groupName: 'Button functionality',
106 | defaultOpen: true,
107 | props: [
108 | {
109 | name: 'type',
110 | label: 'Type',
111 | type: types.SideEditPropType.Select,
112 | selectOptions: {
113 | display: types.OptionsDisplay.Radio,
114 | options: [
115 | { value: 'link', label: 'Link' },
116 | { value: 'button', label: 'Form Button' },
117 | ],
118 | },
119 | },
120 | {
121 | name: 'href',
122 | label: 'Link (external or path)',
123 | type: types.SideEditPropType.Text,
124 | show: (props) => props.type === 'link',
125 | },
126 | {
127 | name: 'isTargetBlank',
128 | label: 'Open in new window',
129 | type: types.SideEditPropType.Boolean,
130 | show: (props) => props.type === 'link',
131 | },
132 | {
133 | name: 'simpleAnchorLink',
134 | label: 'Simple anchor (no SPA link)',
135 | type: types.SideEditPropType.Boolean,
136 | show: (props) => props.type === 'link',
137 | },
138 | {
139 | name: 'buttonType',
140 | label: 'Button type',
141 | type: types.SideEditPropType.Select,
142 | selectOptions: {
143 | display: types.OptionsDisplay.Radio,
144 | options: [
145 | { value: 'submit', label: 'Form submit' },
146 | { value: 'reset', label: 'Form reset' },
147 | { value: 'button', label: 'Button' },
148 | ],
149 | },
150 | show: (props) => props.type === 'button',
151 | },
152 | ],
153 | },
154 | {
155 | groupName: 'Visual',
156 | props: [
157 | {
158 | name: 'variant',
159 | label: 'Variant',
160 | type: types.SideEditPropType.Select,
161 | selectOptions: {
162 | display: types.OptionsDisplay.Radio,
163 | options: [
164 | { value: 'solid', label: 'Solid' },
165 | { value: 'outline', label: 'Outline' },
166 | ],
167 | },
168 | },
169 | {
170 | name: 'padding',
171 | label: 'Size',
172 | type: types.SideEditPropType.Select,
173 | selectOptions: {
174 | display: types.OptionsDisplay.Radio,
175 | options: [
176 | { value: 'normal', label: 'Normal' },
177 | { value: 'small', label: 'Small' },
178 | ],
179 | },
180 | },
181 | ],
182 | },
183 | ],
184 | }
185 |
186 | export default Button
187 |
--------------------------------------------------------------------------------
/react-bricks/bricks/layout/Footer.tsx:
--------------------------------------------------------------------------------
1 | import React from 'react'
2 | import { RichText, Image, Repeater, types, Link } from 'react-bricks/frontend'
3 |
4 | import styles from '../../../css/Footer.module.css'
5 |
6 | interface FooterProps {}
7 |
8 | const Footer: types.Brick = ({}) => {
9 | return (
10 |
45 | )
46 | }
47 |
48 | Footer.schema = {
49 | name: 'footer',
50 | label: 'Footer',
51 | category: 'layout',
52 | tags: ['footer'],
53 | repeaterItems: [
54 | {
55 | name: 'columns',
56 | itemType: 'footer-column',
57 | max: 4,
58 | },
59 | ],
60 | // Defaults when a new brick is added
61 | getDefaultProps: () => ({
62 | logo: {
63 | src: 'https://images.reactbricks.com/original/7fd7ef1a-928f-45d6-b7a7-ff34bf91c15e.svg',
64 | placeholderSrc:
65 | 'https://images.reactbricks.com/original/7fd7ef1a-928f-45d6-b7a7-ff34bf91c15e.svg',
66 | srcSet: '',
67 | alt: 'React Bricks',
68 | seoName: 'react-bricks',
69 | width: 1700.787,
70 | height: 377.953,
71 | },
72 | copyright: [
73 | {
74 | type: 'paragraph',
75 | children: [
76 | {
77 | text: '© React Bricks, Inc.',
78 | },
79 | ],
80 | },
81 | {
82 | type: 'paragraph',
83 | children: [
84 | {
85 | text: 'Proudly made in Italy',
86 | },
87 | ],
88 | },
89 | ],
90 | columns: [
91 | {
92 | title: 'Company',
93 | links: [
94 | {
95 | linkText: 'About us',
96 | linkPath: '/',
97 | },
98 | {
99 | linkText: 'Why React Bricks?',
100 | linkPath: '/',
101 | },
102 | {
103 | linkText: 'Terms of service',
104 | linkPath: '/',
105 | },
106 | {
107 | linkText: 'Privacy',
108 | linkPath: '/',
109 | },
110 | ],
111 | },
112 | {
113 | title: 'Features',
114 | links: [
115 | {
116 | linkText: 'Visual editing',
117 | linkPath: '/',
118 | },
119 | {
120 | linkText: 'React components',
121 | linkPath: '/',
122 | },
123 | {
124 | linkText: 'Enterprise-ready',
125 | linkPath: '/',
126 | },
127 | {
128 | linkText: 'Roadmap',
129 | linkPath: '/',
130 | },
131 | ],
132 | },
133 | {
134 | title: 'Use cases',
135 | links: [
136 | {
137 | linkText: 'Content editors',
138 | linkPath: '/',
139 | },
140 | {
141 | linkText: 'Developers',
142 | linkPath: '/',
143 | },
144 | {
145 | linkText: 'Enterprises',
146 | linkPath: '/',
147 | },
148 | ],
149 | },
150 | {
151 | title: 'Learn',
152 | links: [
153 | {
154 | linkText: 'Tutorial',
155 | linkPath: '/',
156 | },
157 | {
158 | linkText: 'Documentation',
159 | linkPath: '/',
160 | },
161 | {
162 | linkText: 'Videos',
163 | linkPath: '/',
164 | },
165 | {
166 | linkText: 'Blog',
167 | linkPath: '/',
168 | },
169 | ],
170 | },
171 | ],
172 | }),
173 |
174 | // Sidebar Edit controls for props
175 | sideEditProps: [],
176 | }
177 |
178 | export default Footer
179 |
--------------------------------------------------------------------------------
/react-bricks/bricks/layout/FooterColumn.tsx:
--------------------------------------------------------------------------------
1 | import React from "react"
2 | import { Text, Repeater, types } from "react-bricks/frontend"
3 | import styles from "../../../css/FooterColumn.module.css"
4 |
5 | interface FooterColumnProps {}
6 |
7 | const FooterColumn: types.Brick = (props) => {
8 | return (
9 |
10 |
(
14 | {children}
15 | )}
16 | />
17 |
18 |
19 | )
20 | }
21 |
22 | FooterColumn.schema = {
23 | name: "footer-column",
24 | label: "Column",
25 | category: "layout",
26 | hideFromAddMenu: true,
27 | // tags: [],
28 | repeaterItems: [
29 | {
30 | name: "links",
31 | itemType: "footer-link",
32 | },
33 | ],
34 |
35 | // Defaults when a new brick is added
36 | getDefaultProps: () => ({
37 | title: "Features",
38 | }),
39 |
40 | // Sidebar Edit controls for props
41 | sideEditProps: [],
42 | }
43 |
44 | export default FooterColumn
45 |
--------------------------------------------------------------------------------
/react-bricks/bricks/layout/FooterLink.tsx:
--------------------------------------------------------------------------------
1 | import React from "react"
2 | import { Text, types, Link } from "react-bricks/frontend"
3 |
4 | import styles from "../../../css/FooterLink.module.css"
5 |
6 | interface FooterLinkProps {
7 | linkPath: string
8 | }
9 |
10 | const FooterLink: types.Brick = ({ linkPath }) => {
11 | return (
12 |
13 | (
17 | {children}
18 | )}
19 | />
20 |
21 | )
22 | }
23 |
24 | FooterLink.schema = {
25 | name: "footer-link",
26 | label: "Link",
27 | category: "layout",
28 | hideFromAddMenu: true,
29 | // tags: [],
30 |
31 | // Defaults when a new brick is added
32 | getDefaultProps: () => ({
33 | linkText: "Pricing",
34 | linkPath: "/",
35 | }),
36 |
37 | // Sidebar Edit controls for props
38 | sideEditProps: [
39 | {
40 | name: "linkPath",
41 | label: "Link to...",
42 | type: types.SideEditPropType.Text,
43 | },
44 | ],
45 | }
46 |
47 | export default FooterLink
48 |
--------------------------------------------------------------------------------
/react-bricks/bricks/layout/Header.tsx:
--------------------------------------------------------------------------------
1 | import React, { useEffect, useRef, useState } from 'react'
2 | import {
3 | Image,
4 | Repeater,
5 | types,
6 | Link,
7 | useAdminContext,
8 | } from 'react-bricks/frontend'
9 | import { useReactBricksContext } from 'react-bricks/frontend'
10 | import { BsMoonFill, BsSunFill } from 'react-icons/bs'
11 | import { FiMenu, FiX } from 'react-icons/fi'
12 | import useOnClickOutside from './useClickOutside'
13 | import { useTheme } from 'next-themes'
14 |
15 | import styles from '../../../css/Header.module.css'
16 |
17 | interface HeaderProps {}
18 |
19 | const Header: types.Brick = ({}) => {
20 | const [mobileMenuOpen, setMobileMenuOpen] = useState(false)
21 | const { isDarkColorMode, toggleColorMode } = useReactBricksContext()
22 | const { theme } = useTheme()
23 | const { isAdmin } = useAdminContext()
24 |
25 | const currentTheme = isAdmin ? (isDarkColorMode ? 'dark' : 'light') : theme
26 |
27 | const [mounted, setMounted] = useState(false)
28 |
29 | useEffect(() => {
30 | setMounted(true)
31 | }, [])
32 |
33 | const ref = useRef(null)
34 | useOnClickOutside(ref, () => setMobileMenuOpen(false))
35 |
36 | return (
37 |
38 |
104 |
105 | )
106 | }
107 |
108 | Header.schema = {
109 | name: 'header',
110 | label: 'Header',
111 | category: 'layout',
112 | tags: ['header', 'menu'],
113 | repeaterItems: [
114 | {
115 | name: 'menuItems',
116 | itemType: 'header-menu-item',
117 | itemLabel: 'Item',
118 | min: 0,
119 | max: 6,
120 | },
121 | {
122 | name: 'buttons',
123 | itemType: 'button',
124 | itemLabel: 'Button',
125 | min: 0,
126 | max: 2,
127 | },
128 | ],
129 | sideEditProps: [],
130 | getDefaultProps: () => ({
131 | menuItems: [
132 | {
133 | linkPath: '/',
134 | linkText: 'Home',
135 | },
136 | {
137 | linkPath: '/about-us',
138 | linkText: 'About us',
139 | },
140 | {
141 | linkPath: '',
142 | linkText: 'Features',
143 | submenuItems: [
144 | {
145 | linkText: 'Visual editing',
146 | linkDescription:
147 | 'The best visual experience for your content editors',
148 | linkPath: '/',
149 | },
150 | ],
151 | },
152 | ],
153 | logo: {
154 | src: 'https://images.reactbricks.com/original/8d0eb40f-6e1a-4f6c-9895-a06767fcf5fa.svg',
155 | placeholderSrc:
156 | 'https://images.reactbricks.com/original/8d0eb40f-6e1a-4f6c-9895-a06767fcf5fa.svg',
157 | srcSet: '',
158 | width: 450,
159 | height: 100,
160 | alt: 'React Bricks',
161 | seoName: 'react-bricks',
162 | },
163 | buttons: [
164 | {
165 | text: 'Edit content',
166 | href: '/admin',
167 | isTargetBlank: false,
168 | type: 'link',
169 | variant: 'solid',
170 | padding: 'small',
171 | },
172 | ],
173 | }),
174 | }
175 |
176 | export default Header
177 |
--------------------------------------------------------------------------------
/react-bricks/bricks/layout/HeaderMenuItem.tsx:
--------------------------------------------------------------------------------
1 | import React, { useRef, useState } from 'react'
2 | import { Text, Repeater, types, Link, Plain } from 'react-bricks/frontend'
3 | import useOnClickOutside from './useClickOutside'
4 |
5 | import styles from '../../../css/HeaderMenuItem.module.css'
6 |
7 | interface HeaderMenuItemProps {
8 | linkPath: string
9 | linkText: any
10 | submenuItems: any
11 | mobileRef?: React.MutableRefObject
12 | setMobileMenuOpen?: React.Dispatch>
13 | }
14 |
15 | const HeaderMenuItem: types.Brick = ({
16 | linkPath,
17 | linkText,
18 | submenuItems,
19 | mobileRef,
20 | setMobileMenuOpen,
21 | }) => {
22 | const [open, setOpen] = useState(false)
23 | const ref = useRef(null)
24 |
25 | useOnClickOutside(ref, () => setOpen(false))
26 | useOnClickOutside(mobileRef, () => setMobileMenuOpen(false))
27 | if (!submenuItems || !submenuItems.length) {
28 | return (
29 |
30 |
35 |
{children}}
39 | />
40 |
41 |
42 | setMobileMenuOpen(false)}>
43 | {' '}
44 | {typeof linkText === 'string'
45 | ? linkText
46 | : Plain.serialize(linkText)}
47 |
48 |
49 |
50 | )
51 | }
52 |
53 | return (
54 |
55 |
56 |
94 | {open && (
95 |
96 |
(
99 | setOpen((current) => !current)}
102 | >
103 | {props}
104 |
105 | )}
106 | />
107 |
108 | )}
109 |
110 |
111 |
112 |
113 | {typeof linkText === 'string' ? linkText : Plain.serialize(linkText)}
114 |
115 |
(
118 | setMobileMenuOpen(false)}>
119 | {props}
120 |
121 | )}
122 | />
123 |
124 |
125 | )
126 | }
127 |
128 | HeaderMenuItem.schema = {
129 | name: 'header-menu-item',
130 | label: 'Menu Item',
131 | category: 'layout',
132 | hideFromAddMenu: true,
133 |
134 | repeaterItems: [
135 | {
136 | name: 'submenuItems',
137 | itemType: 'header-menu-sub-item',
138 | },
139 | ],
140 |
141 | getDefaultProps: () => ({
142 | submenuItems: [],
143 | linkPath: '/about-us',
144 | isActive: false,
145 | linkText: 'About us',
146 | }),
147 |
148 | sideEditProps: [
149 | {
150 | name: 'linkPath',
151 | label: 'Link to...',
152 | type: types.SideEditPropType.Text,
153 | },
154 | ],
155 | }
156 |
157 | export default HeaderMenuItem
158 |
--------------------------------------------------------------------------------
/react-bricks/bricks/layout/HeaderMenuSubItem.tsx:
--------------------------------------------------------------------------------
1 | import styles from "../../../css/HeaderMenuSubItem.module.css"
2 |
3 | import React from "react"
4 | import { Text, types, Link } from "react-bricks/frontend"
5 | import { FiChevronRight } from "react-icons/fi"
6 |
7 | interface HeaderMenuSubItemProps {
8 | linkPath: string
9 | }
10 |
11 | const HeaderMenuSubItem: types.Brick = ({
12 | linkPath,
13 | }) => {
14 | return (
15 |
16 |
17 |
18 |
19 |
20 |
(
24 | {children}
25 | )}
26 | />
27 |
28 |
(
32 | {children}
33 | )}
34 | />
35 |
36 |
37 |
38 | )
39 | }
40 |
41 | HeaderMenuSubItem.schema = {
42 | name: "header-menu-sub-item",
43 | label: "Submenu Item",
44 | category: "layout",
45 | hideFromAddMenu: true,
46 |
47 | getDefaultProps: () => ({
48 | linkText: "Changelog",
49 | linkDescription: "Release notes for all React Bricks versions",
50 | linkPath: "/",
51 | }),
52 |
53 | sideEditProps: [
54 | {
55 | name: "linkPath",
56 | label: "Link to...",
57 | type: types.SideEditPropType.Text,
58 | },
59 | ],
60 | }
61 |
62 | export default HeaderMenuSubItem
63 |
--------------------------------------------------------------------------------
/react-bricks/bricks/layout/index.ts:
--------------------------------------------------------------------------------
1 | import { types } from "react-bricks/frontend"
2 | import Header from "./Header"
3 | import HeaderMenuItem from "./HeaderMenuItem"
4 | import HeaderMenuSubItem from "./HeaderMenuSubItem"
5 | import Footer from "./Footer"
6 | import FooterColumn from "./FooterColumn"
7 | import FooterLink from "./FooterLink"
8 | import Button from "./Button"
9 |
10 | const layout: types.Brick[] = [
11 | Header,
12 | HeaderMenuItem,
13 | HeaderMenuSubItem,
14 | Footer,
15 | FooterColumn,
16 | FooterLink,
17 | Button,
18 | ]
19 |
20 | export default layout
21 |
--------------------------------------------------------------------------------
/react-bricks/bricks/layout/useClickOutside.ts:
--------------------------------------------------------------------------------
1 | import { MouseEventHandler, RefObject, useEffect } from 'react'
2 |
3 | const useOnClickOutside = (
4 | ref: RefObject,
5 | handler: MouseEventHandler
6 | ) => {
7 | useEffect(() => {
8 | const listener = (event: any) => {
9 | // Do nothing if clicking ref's element or descendent elements
10 | if (!ref?.current || ref.current.contains(event.target)) {
11 | return
12 | }
13 | handler(event)
14 | }
15 | document.addEventListener('mousedown', listener)
16 | document.addEventListener('touchstart', listener)
17 | return () => {
18 | document.removeEventListener('mousedown', listener)
19 | document.removeEventListener('touchstart', listener)
20 | }
21 | }, [ref, handler])
22 | }
23 |
24 | export default useOnClickOutside
25 |
--------------------------------------------------------------------------------
/react-bricks/config.ts:
--------------------------------------------------------------------------------
1 | import Router from "next/router"
2 | import { types } from "react-bricks/frontend"
3 |
4 | import bricks from "./bricks"
5 | import pageTypes from "./pageTypes"
6 | import NextLink from "./NextLink"
7 |
8 | const config: types.ReactBricksConfig = {
9 | appId: process.env.NEXT_PUBLIC_APP_ID,
10 | apiKey: process.env.API_KEY,
11 | environment: process.env.NEXT_PUBLIC_ENVIRONMENT,
12 | bricks,
13 | pageTypes,
14 | customFields: [],
15 | logo: "/logo.svg",
16 | loginUI: {},
17 | contentClassName: "",
18 | //defaultTheme: "",
19 | renderLocalLink: NextLink,
20 | navigate: (path: string) => Router.push(path),
21 | loginPath: "/admin",
22 | editorPath: "/admin/editor",
23 | playgroundPath: "/admin/playground",
24 | appSettingsPath: "/admin/app-settings",
25 | previewPath: "/preview",
26 | //getAdminMenu: () => [],
27 | isDarkColorMode: false,
28 | toggleColorMode: () => {},
29 | useCssInJs: false,
30 | appRootElement: "#__next",
31 | clickToEditSide: types.ClickToEditSide.BottomRight,
32 | //responsiveBreakpoints: [{ type: types.DeviceType.Phone, width: 480, label: "Smartphone" },],
33 | enableAutoSave: true,
34 | disableSaveIfInvalidProps: false,
35 | enablePreview: true,
36 | blockIconsPosition: types.BlockIconsPosition.OutsideBlock,
37 | enableUnsplash: true,
38 | unsplashApiKey: "",
39 | enablePreviewImage: true,
40 | enableDefaultEmbedBrick: true,
41 | //permissions, Fine-grained permissions for enterprise plans
42 | }
43 |
44 | export default config
45 |
--------------------------------------------------------------------------------
/react-bricks/pageTypes.ts:
--------------------------------------------------------------------------------
1 | import { types } from 'react-bricks/frontend'
2 |
3 | const pageTypes: types.IPageType[] = [
4 | {
5 | name: 'page',
6 | pluralName: 'pages',
7 | defaultLocked: false,
8 | defaultStatus: types.PageStatus.Published,
9 | getDefaultContent: () => [],
10 | },
11 | {
12 | name: 'layout',
13 | pluralName: 'layout',
14 | defaultLocked: false,
15 | defaultStatus: types.PageStatus.Published,
16 | getDefaultContent: () => [],
17 | isEntity: true,
18 | allowedBlockTypes: ['header', 'footer'],
19 | },
20 | ]
21 |
22 | export default pageTypes
23 |
--------------------------------------------------------------------------------
/tsconfig.json:
--------------------------------------------------------------------------------
1 | {
2 | "compilerOptions": {
3 | "target": "es5",
4 | "lib": [
5 | "dom",
6 | "dom.iterable",
7 | "esnext"
8 | ],
9 | "allowJs": true,
10 | "skipLibCheck": true,
11 | "strict": false,
12 | "forceConsistentCasingInFileNames": true,
13 | "noEmit": true,
14 | "esModuleInterop": true,
15 | "module": "esnext",
16 | "moduleResolution": "node",
17 | "resolveJsonModule": true,
18 | "isolatedModules": true,
19 | "jsx": "preserve",
20 | "incremental": true
21 | },
22 | "include": [
23 | "next-env.d.ts",
24 | "**/*.ts",
25 | "**/*.tsx"
26 | ],
27 | "exclude": [
28 | "node_modules"
29 | ]
30 | }
31 |
--------------------------------------------------------------------------------