├── .gitignore ├── README.md ├── next.config.js ├── package-lock.json ├── package.json ├── postcss.config.js ├── public ├── Group_2.png ├── akariconsbox@2x.png ├── chevrondown@2x.png ├── darkicon@2x.png ├── frame-2@2x.png ├── group-2@2x.png ├── group@2x.png ├── icon@2x.png ├── iconparkaddtext@2x.png ├── iconparksoliddownone@2x.png ├── index.html ├── ionlogoxbox@2x.png ├── letsiconsback@2x.png ├── lighticon@2x.png ├── lightsocial-icons@2x.png ├── logo@2x.png ├── materialsymbolsimageoutline@2x.png ├── next.svg ├── phcolumns@2x.png ├── pheyebold@2x.png ├── picture-1@2x.png ├── plus@2x.png ├── search@2x.png ├── stack@2x.png ├── swipe@2x.png ├── teenyiconsbuttonoutline@2x.png ├── unsplash-hcpwe1prc@2x.png ├── vector@2x.png └── vercel.svg ├── src ├── app │ ├── editor │ │ └── page.tsx │ ├── favicon.ico │ ├── globals.css │ ├── layout.tsx │ └── page.tsx ├── assets │ ├── image.png │ └── picture 1.svg └── components │ ├── CustomAssetManager.tsx │ ├── CustomBlock.tsx │ ├── CustomLayerManager.tsx │ ├── CustomModal.tsx │ ├── CustomPageManager.tsx │ ├── CustomSelectorManager.tsx │ ├── CustomStyleManager.tsx │ ├── CustomTraitManager.tsx │ ├── LayerItem.tsx │ ├── RightSidebar.tsx │ ├── StylePropertyField.tsx │ ├── TraitPropertyField.tsx │ ├── center │ ├── index.tsx │ └── style.css │ ├── common.ts │ ├── headers │ ├── Topbar.tsx │ └── TopbarButtons.tsx │ ├── home │ └── index.tsx │ ├── leftBlock │ ├── CustomBlockManager.tsx │ ├── MyBlockManager.tsx │ └── index.tsx │ └── theme │ ├── CustomButton.tsx │ ├── HeroImage.tsx │ └── leftblock.module.css ├── tailwind.config.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 | .yarn/install-state.gz 8 | 9 | # testing 10 | /coverage 11 | 12 | # next.js 13 | /.next/ 14 | /out/ 15 | 16 | # production 17 | /build 18 | 19 | # misc 20 | .DS_Store 21 | *.pem 22 | 23 | # debug 24 | npm-debug.log* 25 | yarn-debug.log* 26 | yarn-error.log* 27 | 28 | # local env files 29 | .env*.local 30 | 31 | # vercel 32 | .vercel 33 | 34 | # typescript 35 | *.tsbuildinfo 36 | next-env.d.ts 37 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 |
7 |
8 | 9 |

Nextjs Page Builder By Grapesjs

10 | 11 |

12 |
13 | View Demo 14 |

15 |
16 | 17 | 18 | ## About The Project 19 | 20 | This is a Page builder website it have Home page, Editor page. 21 | 22 | ### Built With 23 | 24 | * Nextjs 25 | * TypeScript 26 | * Material UI 27 | * Tailwind css 28 | * Grapes.js 29 | 30 |

(back to top)

31 | 32 | 33 | ### Installation 34 | 35 | 1. Clone the repo 36 | ```sh 37 | git clone https://github.com/Jutawhid/nextjs-page-builder.git 38 | ``` 39 | 3. Install NPM packages 40 | ```sh 41 | npm install 42 | ``` 43 | 3. Run Project 44 | ```sh 45 | npm run dev 46 | ``` 47 |

(back to top)

48 | 49 | -------------------------------------------------------------------------------- /next.config.js: -------------------------------------------------------------------------------- 1 | /** @type {import('next').NextConfig} */ 2 | const nextConfig = {} 3 | 4 | module.exports = nextConfig 5 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "next-page-builder", 3 | "version": "0.1.0", 4 | "private": true, 5 | "scripts": { 6 | "dev": "next dev", 7 | "build": "next build", 8 | "start": "next start", 9 | "lint": "next lint" 10 | }, 11 | "dependencies": { 12 | "grapesjs": "^0.21.7", 13 | "grapesjs-blocks-basic": "^1.0.2", 14 | "grapesjs-blocks-flexbox": "^1.0.1", 15 | "grapesjs-component-countdown": "^1.0.2", 16 | "grapesjs-custom-code": "^1.0.2", 17 | "grapesjs-navbar": "^1.0.2", 18 | "grapesjs-plugin-forms": "^2.0.6", 19 | "grapesjs-preset-webpage": "^1.0.3", 20 | "grapesjs-style-filter": "^1.0.2", 21 | "grapesjs-tabs": "^1.0.6", 22 | "grapesjs-tooltip": "^0.1.8", 23 | "grapesjs-tui-image-editor": "^1.0.2", 24 | "next": "14.0.4", 25 | "react": "^18", 26 | "react-dom": "^18" 27 | }, 28 | "devDependencies": { 29 | "@types/node": "^20", 30 | "@emotion/react": "^11.5.0", 31 | "@emotion/styled": "^11.3.0", 32 | "@grapesjs/react": "^0.1.0", 33 | "@mdi/js": "^7.2.96", 34 | "@mdi/react": "^1.6.1", 35 | "@mui/material": "^5.13.7", 36 | "@types/backbone": "^1.4.15", 37 | "@types/react": "^18", 38 | "@types/react-dom": "^18", 39 | "autoprefixer": "^10.0.1", 40 | "postcss": "^8", 41 | "tailwindcss": "^3.3.0", 42 | "typescript": "^5" 43 | } 44 | } 45 | -------------------------------------------------------------------------------- /postcss.config.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | plugins: { 3 | tailwindcss: {}, 4 | autoprefixer: {}, 5 | }, 6 | } 7 | -------------------------------------------------------------------------------- /public/Group_2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Jutawhid/nextjs-page-builder/b888c83af3240d1738e6e0f2a48102264bc49947/public/Group_2.png -------------------------------------------------------------------------------- /public/akariconsbox@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Jutawhid/nextjs-page-builder/b888c83af3240d1738e6e0f2a48102264bc49947/public/akariconsbox@2x.png -------------------------------------------------------------------------------- /public/chevrondown@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Jutawhid/nextjs-page-builder/b888c83af3240d1738e6e0f2a48102264bc49947/public/chevrondown@2x.png -------------------------------------------------------------------------------- /public/darkicon@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Jutawhid/nextjs-page-builder/b888c83af3240d1738e6e0f2a48102264bc49947/public/darkicon@2x.png -------------------------------------------------------------------------------- /public/frame-2@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Jutawhid/nextjs-page-builder/b888c83af3240d1738e6e0f2a48102264bc49947/public/frame-2@2x.png -------------------------------------------------------------------------------- /public/group-2@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Jutawhid/nextjs-page-builder/b888c83af3240d1738e6e0f2a48102264bc49947/public/group-2@2x.png -------------------------------------------------------------------------------- /public/group@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Jutawhid/nextjs-page-builder/b888c83af3240d1738e6e0f2a48102264bc49947/public/group@2x.png -------------------------------------------------------------------------------- /public/icon@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Jutawhid/nextjs-page-builder/b888c83af3240d1738e6e0f2a48102264bc49947/public/icon@2x.png -------------------------------------------------------------------------------- /public/iconparkaddtext@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Jutawhid/nextjs-page-builder/b888c83af3240d1738e6e0f2a48102264bc49947/public/iconparkaddtext@2x.png -------------------------------------------------------------------------------- /public/iconparksoliddownone@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Jutawhid/nextjs-page-builder/b888c83af3240d1738e6e0f2a48102264bc49947/public/iconparksoliddownone@2x.png -------------------------------------------------------------------------------- /public/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | locofy-react-project 11 | 12 | 13 | 14 |
15 | 16 | 17 | -------------------------------------------------------------------------------- /public/ionlogoxbox@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Jutawhid/nextjs-page-builder/b888c83af3240d1738e6e0f2a48102264bc49947/public/ionlogoxbox@2x.png -------------------------------------------------------------------------------- /public/letsiconsback@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Jutawhid/nextjs-page-builder/b888c83af3240d1738e6e0f2a48102264bc49947/public/letsiconsback@2x.png -------------------------------------------------------------------------------- /public/lighticon@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Jutawhid/nextjs-page-builder/b888c83af3240d1738e6e0f2a48102264bc49947/public/lighticon@2x.png -------------------------------------------------------------------------------- /public/lightsocial-icons@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Jutawhid/nextjs-page-builder/b888c83af3240d1738e6e0f2a48102264bc49947/public/lightsocial-icons@2x.png -------------------------------------------------------------------------------- /public/logo@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Jutawhid/nextjs-page-builder/b888c83af3240d1738e6e0f2a48102264bc49947/public/logo@2x.png -------------------------------------------------------------------------------- /public/materialsymbolsimageoutline@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Jutawhid/nextjs-page-builder/b888c83af3240d1738e6e0f2a48102264bc49947/public/materialsymbolsimageoutline@2x.png -------------------------------------------------------------------------------- /public/next.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /public/phcolumns@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Jutawhid/nextjs-page-builder/b888c83af3240d1738e6e0f2a48102264bc49947/public/phcolumns@2x.png -------------------------------------------------------------------------------- /public/pheyebold@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Jutawhid/nextjs-page-builder/b888c83af3240d1738e6e0f2a48102264bc49947/public/pheyebold@2x.png -------------------------------------------------------------------------------- /public/picture-1@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Jutawhid/nextjs-page-builder/b888c83af3240d1738e6e0f2a48102264bc49947/public/picture-1@2x.png -------------------------------------------------------------------------------- /public/plus@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Jutawhid/nextjs-page-builder/b888c83af3240d1738e6e0f2a48102264bc49947/public/plus@2x.png -------------------------------------------------------------------------------- /public/search@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Jutawhid/nextjs-page-builder/b888c83af3240d1738e6e0f2a48102264bc49947/public/search@2x.png -------------------------------------------------------------------------------- /public/stack@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Jutawhid/nextjs-page-builder/b888c83af3240d1738e6e0f2a48102264bc49947/public/stack@2x.png -------------------------------------------------------------------------------- /public/swipe@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Jutawhid/nextjs-page-builder/b888c83af3240d1738e6e0f2a48102264bc49947/public/swipe@2x.png -------------------------------------------------------------------------------- /public/teenyiconsbuttonoutline@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Jutawhid/nextjs-page-builder/b888c83af3240d1738e6e0f2a48102264bc49947/public/teenyiconsbuttonoutline@2x.png -------------------------------------------------------------------------------- /public/unsplash-hcpwe1prc@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Jutawhid/nextjs-page-builder/b888c83af3240d1738e6e0f2a48102264bc49947/public/unsplash-hcpwe1prc@2x.png -------------------------------------------------------------------------------- /public/vector@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Jutawhid/nextjs-page-builder/b888c83af3240d1738e6e0f2a48102264bc49947/public/vector@2x.png -------------------------------------------------------------------------------- /public/vercel.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /src/app/editor/page.tsx: -------------------------------------------------------------------------------- 1 | 'use client' 2 | 3 | import * as React from 'react'; 4 | import GjsEditor, { 5 | AssetsProvider, 6 | Canvas, 7 | ModalProvider, 8 | BlocksProvider, 9 | TraitsProvider 10 | } from '@grapesjs/react'; 11 | import type { Editor, EditorConfig } from 'grapesjs'; 12 | import { ThemeProvider, createTheme } from '@mui/material/styles'; 13 | import { MAIN_BORDER_COLOR } from '../../components/common'; 14 | import CustomModal from '../../components/CustomModal'; 15 | import CustomAssetManager from '../../components/CustomAssetManager'; 16 | import Topbar from '../../components/headers/Topbar'; 17 | import CenterArea from '../../components/center'; 18 | import RightSidebar from '../../components/RightSidebar'; 19 | import { Grid, Stack } from '@mui/material'; 20 | import CustomTraitManager from '@/components/CustomTraitManager'; 21 | import LeftBlock from '@/components/leftBlock' 22 | import HeroImage from '@/components/theme/HeroImage'; 23 | import styles from '../../components/theme/leftblock.module.css' 24 | import imgIcon from '../assets/picture 1.svg'; 25 | import CustomButton from '@/components/theme/CustomButton'; 26 | const theme = createTheme({ 27 | palette: { 28 | mode: 'dark', 29 | background: { 30 | default: "#222222" 31 | }, 32 | text: { 33 | primary: "#ffffff" 34 | } 35 | }, 36 | }); 37 | const svgText = ` 38 | 39 | `; 40 | const svgLink = ` 41 | 42 | `; 43 | const svgImage = ` 44 | 45 | `; 46 | 47 | const blocks = [ 48 | { 49 | id: 'image', 50 | label: 'Hero Image', 51 | category: 'My Custom', 52 | media: svgImage, 53 | activate: true, 54 | content: { type: 'image', style: { padding: '10px' } } 55 | }, 56 | { 57 | id: 'button', 58 | label: 'Button', 59 | category: 'My Custom', 60 | media: svgImage, 61 | activate: true, 62 | content: { 63 | type: 'button', 64 | content: , 65 | style: { padding: '10px' }, 66 | } 67 | }, 68 | { 69 | id: 'input', 70 | label: 'Searchbar', 71 | category: 'My Custom', 72 | media: svgImage, 73 | activate: true, 74 | content: { 75 | type: 'input', 76 | content: ``, 77 | style: { padding: '10px' }, 78 | } 79 | 80 | }, { 81 | id: 'image', 82 | label: 'Container', 83 | category: 'Basic', 84 | media: svgImage, 85 | activate: true, 86 | content: { type: 'image' } 87 | } 88 | ]; 89 | const gjsOptions: EditorConfig = { 90 | height: '100vh', 91 | storageManager: false, 92 | undoManager: { trackSelection: false }, 93 | selectorManager: { componentFirst: true }, 94 | projectData: { 95 | assets: [ 96 | 'https://via.placeholder.com/350x250/78c5d6/fff', 97 | 'https://via.placeholder.com/350x250/459ba8/fff', 98 | 'https://via.placeholder.com/350x250/79c267/fff', 99 | 'https://via.placeholder.com/350x250/c5d647/fff', 100 | 'https://via.placeholder.com/350x250/f28c33/fff', 101 | ], 102 | pages: [ 103 | { 104 | name: 'Home page', 105 | component: `

GrapesJS React Custom UI

`, 106 | }, 107 | ], 108 | }, 109 | blockManager: { 110 | custom: true, 111 | blocks, 112 | }, 113 | }; 114 | 115 | export default function Home() { 116 | const onEditor = (editor: Editor) => { 117 | console.log('Editor loaded'); 118 | (window as any).editor = editor; 119 | }; 120 | 121 | return ( 122 | // @ts-ignore 123 | 124 | 137 | 138 | 139 | 140 | 141 | 142 | 143 | 144 | 145 | 146 | 147 | {/* */} 148 | 149 | 150 | 151 | {/* */} 154 | 155 | {(props) => } 156 | 157 | 158 | 159 | 160 | 161 | 162 | 163 | {({ open, title, content, close }) => ( 164 | 170 | )} 171 | 172 | 173 | {({ assets, select, close, Container }) => ( 174 | 175 | 180 | 181 | )} 182 | 183 | 184 | 185 | ); 186 | } 187 | -------------------------------------------------------------------------------- /src/app/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Jutawhid/nextjs-page-builder/b888c83af3240d1738e6e0f2a48102264bc49947/src/app/favicon.ico -------------------------------------------------------------------------------- /src/app/globals.css: -------------------------------------------------------------------------------- 1 | @import url("https://fonts.googleapis.com/css2?family=Ligconsolata:wght@400&display=swap"); 2 | @import url("https://fonts.googleapis.com/css2?family=Inter:wght@600&display=swap"); 3 | @import url("https://fonts.googleapis.com/css2?family=Inconsolata:wght@400&display=swap"); 4 | 5 | @tailwind base; 6 | @tailwind components; 7 | @tailwind utilities; 8 | 9 | /* :root { 10 | --foreground-rgb: 0, 0, 0; 11 | --background-start-rgb: 214, 219, 220; 12 | --background-end-rgb: 255, 255, 255; 13 | } 14 | 15 | @media (prefers-color-scheme: dark) { 16 | :root { 17 | --foreground-rgb: 255, 255, 255; 18 | --background-start-rgb: 0, 0, 0; 19 | --background-end-rgb: 0, 0, 0; 20 | } 21 | } 22 | 23 | body { 24 | color: rgb(var(--foreground-rgb)); 25 | background: linear-gradient( 26 | to bottom, 27 | transparent, 28 | rgb(var(--background-end-rgb)) 29 | ) 30 | rgb(var(--background-start-rgb)); 31 | } */ 32 | -------------------------------------------------------------------------------- /src/app/layout.tsx: -------------------------------------------------------------------------------- 1 | import type { Metadata } from 'next' 2 | import { Inter } from 'next/font/google' 3 | import './globals.css' 4 | 5 | const inter = Inter({ subsets: ['latin'] }) 6 | 7 | export const metadata: Metadata = { 8 | title: 'Create Next App', 9 | description: 'Generated by create next app', 10 | } 11 | 12 | export default function RootLayout({ 13 | children, 14 | }: { 15 | children: React.ReactNode 16 | }) { 17 | return ( 18 | 19 | {children} 20 | 21 | ) 22 | } 23 | -------------------------------------------------------------------------------- /src/app/page.tsx: -------------------------------------------------------------------------------- 1 | 'use client' 2 | 3 | import * as React from 'react'; 4 | import GjsEditor, { 5 | AssetsProvider, 6 | Canvas, 7 | ModalProvider, 8 | BlocksProvider, 9 | TraitsProvider 10 | } from '@grapesjs/react'; 11 | import type { Editor, EditorConfig } from 'grapesjs'; 12 | import { ThemeProvider, createTheme } from '@mui/material/styles'; 13 | import HomeCom from '@/components/home/index'; 14 | const theme = createTheme({ 15 | palette: { 16 | mode: 'dark', 17 | background: { 18 | default: "#222222" 19 | }, 20 | text: { 21 | primary: "#ffffff" 22 | } 23 | }, 24 | }); 25 | 26 | 27 | 28 | 29 | export default function Home() { 30 | const onEditor = (editor: Editor) => { 31 | console.log('Editor loaded'); 32 | (window as any).editor = editor; 33 | }; 34 | 35 | return ( 36 | // @ts-ignore 37 | 38 | 39 | 40 | ); 41 | } 42 | -------------------------------------------------------------------------------- /src/assets/image.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Jutawhid/nextjs-page-builder/b888c83af3240d1738e6e0f2a48102264bc49947/src/assets/image.png -------------------------------------------------------------------------------- /src/assets/picture 1.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | -------------------------------------------------------------------------------- /src/components/CustomAssetManager.tsx: -------------------------------------------------------------------------------- 1 | import * as React from 'react'; 2 | import { AssetsResultProps, useEditor } from '@grapesjs/react'; 3 | import { mdiClose } from '@mdi/js'; 4 | import Icon from '@mdi/react'; 5 | import type { Asset } from 'grapesjs'; 6 | import { BTN_CLS } from './common'; 7 | 8 | export type CustomAssetManagerProps = Pick< 9 | AssetsResultProps, 10 | 'assets' | 'close' | 'select' 11 | >; 12 | 13 | export default function CustomAssetManager({ 14 | assets, 15 | select, 16 | }: CustomAssetManagerProps) { 17 | const editor = useEditor(); 18 | 19 | const remove = (asset: Asset) => { 20 | editor.Assets.remove(asset); 21 | }; 22 | 23 | return ( 24 |
25 | {assets.map((asset) => ( 26 |
30 | 31 |
32 | 39 | 46 |
47 |
48 | ))} 49 |
50 | ); 51 | } 52 | -------------------------------------------------------------------------------- /src/components/CustomBlock.tsx: -------------------------------------------------------------------------------- 1 | // CustomBlock.js 2 | import React from 'react'; 3 | 4 | const CustomBlock = ({ data }:any) => { 5 | return ( 6 |
7 |

{data.text}

8 |
9 | ); 10 | }; 11 | 12 | export default CustomBlock; 13 | -------------------------------------------------------------------------------- /src/components/CustomLayerManager.tsx: -------------------------------------------------------------------------------- 1 | import * as React from 'react'; 2 | import { LayersResultProps, useEditor } from '@grapesjs/react'; 3 | import type { Component, Editor } from 'grapesjs'; 4 | import { useRef, useState } from 'react'; 5 | import { cx } from './common'; 6 | import LayerItem from './LayerItem'; 7 | 8 | type DragRect = { 9 | y: number; 10 | h: number; 11 | pointerInside: boolean; 12 | }; 13 | 14 | const wrapGridStyle = { 15 | touchAction: 'none', 16 | }; 17 | 18 | const LAYER_PAD = 5; 19 | 20 | const getDragTarget = (ev: React.PointerEvent) => { 21 | const el = document.elementFromPoint(ev.clientX, ev.clientY) as HTMLElement; 22 | const elLayer = el?.closest('[data-layer-item]') as HTMLElement; 23 | return { 24 | el: elLayer, 25 | cmp: (elLayer as any)?.__cmp as Component, 26 | }; 27 | }; 28 | 29 | type CanMoveResult = ReturnType; 30 | 31 | interface CanMove extends Partial> { 32 | canMoveInside?: CanMoveResult; 33 | source?: Component | null; 34 | index?: number; 35 | } 36 | 37 | export default function CustomLayerManager({ 38 | root, 39 | }: Omit) { 40 | const editor = useEditor(); 41 | const [pointerDown, setPointerDown] = useState(false); 42 | const [canMoveRes, setCanMoveRes] = useState({}); 43 | const [cmpPointerOver, setCmpPointerOver] = useState(); 44 | const [dragging, setDragging] = useState(); 45 | const [dragParent, setDragParent] = useState(); 46 | const [dragRect, setDragRect] = useState(); 47 | const indicatorRef = useRef(null); 48 | const { Components } = editor; 49 | 50 | const onDragStart = () => { 51 | setPointerDown(true); 52 | }; 53 | 54 | const onDragMove = (ev: React.PointerEvent) => { 55 | if (!pointerDown) return; 56 | const { cmp, el: elLayer } = getDragTarget(ev); 57 | if (!elLayer || !cmp) return; 58 | const layerRect = elLayer.getBoundingClientRect(); 59 | const layerH = elLayer.offsetHeight; 60 | const layerY = elLayer.offsetTop; 61 | const pointerY = ev.clientY; 62 | const isBefore = pointerY < layerRect.y + layerH / 2; 63 | const cmpSource = !dragging ? cmp : dragging; 64 | const cmpTarget = cmp.parent(); 65 | const cmpIndex = cmp.index() + (isBefore ? 0 : 1); 66 | !dragging && setDragging(cmp); 67 | setCmpPointerOver(cmp); 68 | const canMove = Components.canMove(cmpTarget!, cmpSource, cmpIndex); 69 | const canMoveInside = Components.canMove(cmp, cmpSource); 70 | const canMoveRes: CanMove = { 71 | ...canMove, 72 | canMoveInside, 73 | index: cmpIndex, 74 | }; 75 | let pointerInside = false; 76 | if ( 77 | canMoveInside.result && 78 | pointerY > layerRect.y + LAYER_PAD && 79 | pointerY < layerRect.y + layerH - LAYER_PAD 80 | ) { 81 | pointerInside = true; 82 | canMoveRes.target = cmp; 83 | delete canMoveRes.index; 84 | } 85 | setDragParent(pointerInside ? cmp : undefined); 86 | setCanMoveRes(canMoveRes); 87 | setDragRect({ 88 | pointerInside, 89 | y: layerY + (isBefore ? 0 : layerH), 90 | h: layerH, 91 | }); 92 | }; 93 | const onDragEnd = () => { 94 | canMoveRes?.result && 95 | canMoveRes.source?.move(canMoveRes.target!, { at: canMoveRes.index }); 96 | setCanMoveRes({}); 97 | setPointerDown(false); 98 | setDragging(undefined); 99 | setCmpPointerOver(undefined); 100 | setDragParent(undefined); 101 | setDragRect(undefined); 102 | }; 103 | 104 | const dragLevel = (cmpPointerOver ? cmpPointerOver.parents() : []).length; 105 | const showIndicator = !!( 106 | dragging && 107 | dragRect && 108 | canMoveRes?.result && 109 | !dragRect.pointerInside 110 | ); 111 | const indicatorStyle = showIndicator 112 | ? { top: dragRect.y, left: 0, marginLeft: dragLevel * 10 + 20 } 113 | : {}; 114 | 115 | return ( 116 |
123 | {!!root && ( 124 | 130 | )} 131 | {showIndicator && ( 132 |
137 | )} 138 |
139 | ); 140 | } 141 | -------------------------------------------------------------------------------- /src/components/CustomModal.tsx: -------------------------------------------------------------------------------- 1 | import * as React from 'react'; 2 | import { mdiClose } from '@mdi/js'; 3 | import Icon from '@mdi/react'; 4 | import Box from '@mui/material/Box'; 5 | import Fade from '@mui/material/Fade'; 6 | import Modal, { ModalProps } from '@mui/material/Modal'; 7 | import { MAIN_BG_COLOR, MAIN_TXT_COLOR, cx } from './common'; 8 | 9 | const style = { 10 | position: 'absolute', 11 | top: '50%', 12 | left: '50%', 13 | transform: 'translate(-50%, -50%)', 14 | width: 900, 15 | border: '2px solid #000', 16 | boxShadow: 24, 17 | overflow: 'hidden', 18 | display: 'flex', 19 | flexDirection: 'column', 20 | maxHeight: '90vh', 21 | p: 2, 22 | }; 23 | 24 | interface CustomModalProps extends Omit { 25 | title: React.ReactNode; 26 | close: () => void; 27 | } 28 | 29 | export default function CustomModal({ 30 | children, 31 | title, 32 | close, 33 | ...props 34 | }: CustomModalProps) { 35 | return ( 36 | 37 | 38 | 42 |
43 |
{title}
44 |
45 | 46 |
47 |
48 |
{children}
49 |
50 |
51 |
52 | ); 53 | } 54 | -------------------------------------------------------------------------------- /src/components/CustomPageManager.tsx: -------------------------------------------------------------------------------- 1 | import * as React from 'react'; 2 | import { PagesResultProps } from '@grapesjs/react'; 3 | import { BTN_CLS, MAIN_BORDER_COLOR, cx } from './common'; 4 | import Icon from '@mdi/react'; 5 | import { mdiDelete } from '@mdi/js'; 6 | 7 | export default function CustomPageManager({ 8 | pages, 9 | selected, 10 | add, 11 | select, 12 | remove, 13 | }: PagesResultProps) { 14 | const addNewPage = () => { 15 | const nextIndex = pages.length + 1; 16 | add({ 17 | name: `New page ${nextIndex}`, 18 | component: `

Page content ${nextIndex}

`, 19 | }); 20 | }; 21 | 22 | return ( 23 |
24 |
25 | 28 |
29 | {pages.map((page, index) => ( 30 |
38 | 45 | {selected !== page && ( 46 | 49 | )} 50 |
51 | ))} 52 |
53 | ); 54 | } 55 | -------------------------------------------------------------------------------- /src/components/CustomSelectorManager.tsx: -------------------------------------------------------------------------------- 1 | import * as React from 'react'; 2 | import { SelectorsResultProps } from '@grapesjs/react'; 3 | import { mdiClose, mdiPlus } from '@mdi/js'; 4 | import Icon from '@mdi/react'; 5 | import FormControl from '@mui/material/FormControl'; 6 | import MenuItem from '@mui/material/MenuItem'; 7 | import Select from '@mui/material/Select'; 8 | import { MAIN_BORDER_COLOR, cx } from './common'; 9 | 10 | export default function CustomSelectorManager({ 11 | selectors, 12 | selectedState, 13 | states, 14 | targets, 15 | setState, 16 | addSelector, 17 | removeSelector, 18 | }: Omit) { 19 | const addNewSelector = () => { 20 | const next = selectors.length + 1; 21 | addSelector({ name: `new-${next}`, label: `New ${next}` }); 22 | }; 23 | 24 | const targetStr = targets.join(', '); 25 | 26 | return ( 27 |
28 |
29 |
Selectors
30 | 31 | 43 | 44 |
45 |
51 | {targetStr ? ( 52 | 59 | ) : ( 60 |
Select a component
61 | )} 62 | {selectors.map((selector) => ( 63 |
67 |
{selector.getLabel()}
68 | 71 |
72 | ))} 73 |
74 |
75 | Selected: {targetStr || 'None'} 76 |
77 |
78 | ); 79 | } 80 | -------------------------------------------------------------------------------- /src/components/CustomStyleManager.tsx: -------------------------------------------------------------------------------- 1 | import * as React from 'react'; 2 | import { StylesResultProps } from '@grapesjs/react'; 3 | import { mdiMenuDown } from '@mdi/js'; 4 | import Icon from '@mdi/react'; 5 | import Accordion from '@mui/material/Accordion'; 6 | import AccordionDetails from '@mui/material/AccordionDetails'; 7 | import AccordionSummary from '@mui/material/AccordionSummary'; 8 | import { MAIN_BG_COLOR } from './common'; 9 | import StylePropertyField from './StylePropertyField'; 10 | 11 | const accordionIcon = ; 12 | 13 | export default function CustomStyleManager({ 14 | sectors, 15 | }: Omit) { 16 | return ( 17 |
18 | {sectors.map((sector) => ( 19 | 20 | 24 | {sector.getName()} 25 | 26 | 27 | {sector.getProperties().map((prop) => ( 28 | 29 | ))} 30 | 31 | 32 | ))} 33 |
34 | ); 35 | } 36 | -------------------------------------------------------------------------------- /src/components/CustomTraitManager.tsx: -------------------------------------------------------------------------------- 1 | import * as React from 'react'; 2 | import { TraitsResultProps } from '@grapesjs/react'; 3 | import TraitPropertyField from './TraitPropertyField'; 4 | 5 | export default function CustomTraitManager({ traits }: Omit) { 6 | return ( 7 |
8 | { 9 | !traits.length ? 10 |
No properties available
11 | : 12 | traits.map(trait => ( 13 | 14 | ))} 15 |
16 | ); 17 | } -------------------------------------------------------------------------------- /src/components/LayerItem.tsx: -------------------------------------------------------------------------------- 1 | import * as React from 'react'; 2 | import { useEditor } from '@grapesjs/react'; 3 | import { mdiEyeOffOutline, mdiEyeOutline, mdiMenuDown } from '@mdi/js'; 4 | import Icon from '@mdi/react'; 5 | import type { Component } from 'grapesjs'; 6 | import { MouseEvent, useEffect, useMemo, useRef, useState } from 'react'; 7 | import { MAIN_BORDER_COLOR, cx } from './common'; 8 | 9 | export declare interface LayerItemProps 10 | extends React.HTMLProps { 11 | component: Component; 12 | level: number; 13 | draggingCmp?: Component; 14 | dragParent?: Component; 15 | } 16 | 17 | const itemStyle = { maxWidth: `100%` }; 18 | 19 | export default function LayerItem({ 20 | component, 21 | draggingCmp, 22 | dragParent, 23 | ...props 24 | }: LayerItemProps) { 25 | const editor = useEditor(); 26 | const { Layers } = editor; 27 | const layerRef = useRef(null); 28 | const [layerData, setLayerData] = useState(Layers.getLayerData(component)); 29 | const { open, selected, hovered, components, visible, name } = layerData; 30 | const componentsIds = components.map((cmp) => cmp.getId()); 31 | const isDragging = draggingCmp === component; 32 | const cmpHash = componentsIds.join('-'); 33 | const level = props.level + 1; 34 | const isHovered = hovered || dragParent === component; 35 | 36 | useEffect(() => { 37 | level === 0 && setLayerData(Layers.getLayerData(component)); 38 | if (layerRef.current) { 39 | (layerRef.current as any).__cmp = component; 40 | } 41 | }, [component]); 42 | 43 | useEffect(() => { 44 | const up = (cmp: Component) => { 45 | cmp === component && setLayerData(Layers.getLayerData(cmp)); 46 | }; 47 | const ev = Layers.events.component; 48 | editor.on(ev, up); 49 | 50 | return () => { 51 | editor.off(ev, up); 52 | }; 53 | }, [editor, Layers, component]); 54 | 55 | const cmpToRender = useMemo(() => { 56 | return components.map((cmp) => ( 57 | 64 | )); 65 | }, [cmpHash, draggingCmp, dragParent]); 66 | 67 | const toggleOpen = (ev: MouseEvent) => { 68 | ev.stopPropagation(); 69 | Layers.setLayerData(component, { open: !open }); 70 | }; 71 | 72 | const toggleVisibility = (ev: MouseEvent) => { 73 | ev.stopPropagation(); 74 | Layers.setLayerData(component, { visible: !visible }); 75 | }; 76 | 77 | const select = (event: MouseEvent) => { 78 | event.stopPropagation(); 79 | Layers.setLayerData(component, { selected: true }, { event }); 80 | }; 81 | 82 | const hover = (hovered: boolean) => { 83 | if (!hovered || !draggingCmp) { 84 | Layers.setLayerData(component, { hovered }); 85 | } 86 | }; 87 | 88 | const wrapperCls = cx( 89 | 'layer-item flex flex-col', 90 | selected && 'bg-sky-900', 91 | (!visible || isDragging) && 'opacity-50' 92 | ); 93 | 94 | return ( 95 |
96 |
hover(true)} 99 | onMouseLeave={() => hover(false)} 100 | className="group max-w-full" 101 | data-layer-item 102 | ref={layerRef} 103 | > 104 |
113 |
121 | 122 |
123 |
124 | {name} 125 |
126 |
133 | 137 |
138 |
139 |
140 | {!!(open && components.length) && ( 141 |
{cmpToRender}
142 | )} 143 |
144 | ); 145 | } 146 | -------------------------------------------------------------------------------- /src/components/RightSidebar.tsx: -------------------------------------------------------------------------------- 1 | import * as React from 'react'; 2 | import { 3 | BlocksProvider, 4 | LayersProvider, 5 | PagesProvider, 6 | SelectorsProvider, 7 | StylesProvider, 8 | TraitsProvider, 9 | } from '@grapesjs/react'; 10 | import { 11 | mdiBrush, 12 | mdiLayers, 13 | mdiViewGridPlus, 14 | mdiTextBoxMultiple, 15 | mdiCog, 16 | } from '@mdi/js'; 17 | import Icon from '@mdi/react'; 18 | import Tab from '@mui/material/Tab'; 19 | import Tabs from '@mui/material/Tabs'; 20 | import { useState } from 'react'; 21 | import CustomBlockManager from './leftBlock/CustomBlockManager'; 22 | import { MAIN_BORDER_COLOR, cx } from './common'; 23 | import CustomPageManager from './CustomPageManager'; 24 | import CustomLayerManager from './CustomLayerManager'; 25 | import CustomSelectorManager from './CustomSelectorManager'; 26 | import CustomStyleManager from './CustomStyleManager'; 27 | import CustomTraitManager from './CustomTraitManager'; 28 | 29 | const defaultTabProps = { 30 | className: '!min-w-0', 31 | }; 32 | 33 | export default function RightSidebar({ 34 | className, 35 | }: React.HTMLAttributes) { 36 | const [selectedTab, setSelectedTab] = useState(0); 37 | 38 | return ( 39 |
40 | setSelectedTab(v)} 43 | variant="fullWidth" 44 | > 45 | } /> 46 | } /> 47 | } /> 48 | } 51 | /> 52 | } 55 | /> 56 | 57 |
60 | {selectedTab === 0 && ( 61 | <> 62 | 63 | {(props) => } 64 | 65 | 66 | {(props) => } 67 | 68 | 69 | )} 70 | {selectedTab === 1 && ( 71 | 72 | {(props) => } 73 | 74 | )} 75 | {selectedTab === 2 && ( 76 | 77 | {(props) => } 78 | 79 | )} 80 | {selectedTab === 3 && ( 81 | 82 | {(props) => } 83 | 84 | )} 85 | {selectedTab === 4 && ( 86 | 87 | {(props) => } 88 | 89 | )} 90 |
91 |
92 | ); 93 | } 94 | -------------------------------------------------------------------------------- /src/components/StylePropertyField.tsx: -------------------------------------------------------------------------------- 1 | import * as React from 'react'; 2 | import { useEditor } from '@grapesjs/react'; 3 | import { 4 | mdiArrowDownDropCircle, 5 | mdiArrowUpDropCircle, 6 | mdiClose, 7 | mdiDelete, 8 | mdiPlus, 9 | } from '@mdi/js'; 10 | import Icon from '@mdi/react'; 11 | import FormControl from '@mui/material/FormControl'; 12 | import FormControlLabel from '@mui/material/FormControlLabel'; 13 | import IconButton from '@mui/material/IconButton'; 14 | import InputAdornment from '@mui/material/InputAdornment'; 15 | import MenuItem from '@mui/material/MenuItem'; 16 | import Radio from '@mui/material/Radio'; 17 | import RadioGroup from '@mui/material/RadioGroup'; 18 | import Select from '@mui/material/Select'; 19 | import Slider from '@mui/material/Slider'; 20 | import TextField from '@mui/material/TextField'; 21 | import type { 22 | Property, 23 | PropertyComposite, 24 | PropertyRadio, 25 | PropertySelect, 26 | PropertySlider, 27 | PropertyStack, 28 | } from 'grapesjs'; 29 | import { BTN_CLS, ROUND_BORDER_COLOR, cx } from './common'; 30 | 31 | interface StylePropertyFieldProps extends React.HTMLProps { 32 | prop: Property; 33 | } 34 | 35 | export default function StylePropertyField({ 36 | prop, 37 | ...rest 38 | }: StylePropertyFieldProps) { 39 | const editor = useEditor(); 40 | const handleChange = (value: string) => { 41 | prop.upValue(value); 42 | }; 43 | 44 | const onChange = (ev: any) => { 45 | handleChange(ev.target.value); 46 | }; 47 | 48 | const openAssets = () => { 49 | const { Assets } = editor; 50 | Assets.open({ 51 | select: (asset, complete) => { 52 | console.log({ complete }); 53 | prop.upValue(asset.getSrc(), { partial: !complete }); 54 | complete && Assets.close(); 55 | }, 56 | types: ['image'], 57 | accept: 'image/*', 58 | }); 59 | }; 60 | 61 | const type = prop.getType(); 62 | const defValue = prop.getDefaultValue(); 63 | const canClear = prop.canClear(); 64 | const hasValue = prop.hasValue(); 65 | const value = prop.getValue(); 66 | const valueString = hasValue ? value : ''; 67 | const valueWithDef = hasValue ? value : defValue; 68 | 69 | let inputToRender = ( 70 | 77 | ); 78 | 79 | switch (type) { 80 | case 'radio': 81 | { 82 | const radioProp = prop as PropertyRadio; 83 | inputToRender = ( 84 | 85 | {radioProp.getOptions().map((option) => ( 86 | } 91 | /> 92 | ))} 93 | 94 | ); 95 | } 96 | break; 97 | case 'select': 98 | { 99 | const selectProp = prop as PropertySelect; 100 | inputToRender = ( 101 | 102 | 112 | 113 | ); 114 | } 115 | break; 116 | case 'color': 117 | { 118 | inputToRender = ( 119 | 128 |
132 | handleChange(ev.target.value)} 137 | /> 138 |
139 | 140 | ), 141 | }} 142 | /> 143 | ); 144 | } 145 | break; 146 | case 'slider': 147 | { 148 | const sliderProp = prop as PropertySlider; 149 | inputToRender = ( 150 | 159 | ); 160 | } 161 | break; 162 | case 'file': 163 | { 164 | inputToRender = ( 165 |
166 | {value && value !== defValue && ( 167 |
handleChange('')} 171 | /> 172 | )} 173 | 176 |
177 | ); 178 | } 179 | break; 180 | case 'composite': 181 | { 182 | const compositeProp = prop as PropertyComposite; 183 | inputToRender = ( 184 |
187 | {compositeProp.getProperties().map((prop) => ( 188 | 189 | ))} 190 |
191 | ); 192 | } 193 | break; 194 | case 'stack': 195 | { 196 | const stackProp = prop as PropertyStack; 197 | const layers = stackProp.getLayers(); 198 | const isTextShadow = stackProp.getName() === 'text-shadow'; 199 | inputToRender = ( 200 |
206 | {layers.map((layer) => ( 207 |
208 |
209 | layer.move(layer.getIndex() - 1)} 212 | > 213 | 214 | 215 | layer.move(layer.getIndex() + 1)} 218 | > 219 | 220 | 221 | 224 |
234 | {isTextShadow && 'T'} 235 |
236 | layer.remove()}> 237 | 238 | 239 |
240 | {layer.isSelected() && ( 241 |
242 | {stackProp.getProperties().map((prop) => ( 243 | 244 | ))} 245 |
246 | )} 247 |
248 | ))} 249 |
250 | ); 251 | } 252 | break; 253 | } 254 | 255 | return ( 256 |
260 |
261 |
{prop.getLabel()}
262 | {canClear && ( 263 | 266 | )} 267 | {type === 'stack' && ( 268 | (prop as PropertyStack).addLayer({}, { at: 0 })} 272 | > 273 | 274 | 275 | )} 276 |
277 | {inputToRender} 278 |
279 | ); 280 | } 281 | -------------------------------------------------------------------------------- /src/components/TraitPropertyField.tsx: -------------------------------------------------------------------------------- 1 | import * as React from 'react'; 2 | import { useEditor } from '@grapesjs/react'; 3 | import Button from '@mui/material/Button'; 4 | import Checkbox from '@mui/material/Checkbox'; 5 | import FormControl from '@mui/material/FormControl'; 6 | import InputAdornment from '@mui/material/InputAdornment'; 7 | import MenuItem from '@mui/material/MenuItem'; 8 | import Select from '@mui/material/Select'; 9 | import TextField from '@mui/material/TextField'; 10 | import type { Trait } from 'grapesjs'; 11 | import { ROUND_BORDER_COLOR, cx } from './common'; 12 | 13 | interface StylePropertyFieldProps extends React.HTMLProps { 14 | trait: Trait; 15 | } 16 | 17 | export default function TraitPropertyField({ 18 | trait, 19 | ...rest 20 | }: StylePropertyFieldProps) { 21 | const editor = useEditor(); 22 | const handleChange = (value: string) => { 23 | trait.setValue(value); 24 | }; 25 | 26 | const onChange = (ev: any) => { 27 | handleChange(ev.target.value); 28 | }; 29 | 30 | const handleButtonClick = () => { 31 | const command = trait.get('command'); 32 | if (command) { 33 | typeof command === 'string' 34 | ? editor.runCommand(command) 35 | : command(editor, trait); 36 | } 37 | }; 38 | 39 | const type = trait.getType(); 40 | const defValue = trait.getDefault() || trait.attributes.placeholder; 41 | const value = trait.getValue(); 42 | const valueWithDef = typeof value !== 'undefined' ? value : defValue; 43 | 44 | let inputToRender = ( 45 | 52 | ); 53 | 54 | switch (type) { 55 | case 'select': 56 | { 57 | inputToRender = ( 58 | 59 | 69 | 70 | ); 71 | } 72 | break; 73 | case 'color': 74 | { 75 | inputToRender = ( 76 | 85 |
89 | handleChange(ev.target.value)} 94 | /> 95 |
96 | 97 | ), 98 | }} 99 | /> 100 | ); 101 | } 102 | break; 103 | case 'checkbox': 104 | { 105 | inputToRender = ( 106 | trait.setValue(ev.target.checked)} 109 | size="small" 110 | /> 111 | ); 112 | } 113 | break; 114 | case 'button': 115 | { 116 | inputToRender = ( 117 | 120 | ); 121 | } 122 | break; 123 | } 124 | 125 | return ( 126 |
127 |
128 |
{trait.getLabel()}
129 |
130 | {inputToRender} 131 |
132 | ); 133 | } 134 | -------------------------------------------------------------------------------- /src/components/center/index.tsx: -------------------------------------------------------------------------------- 1 | import * as React from 'react'; 2 | 3 | import { Box, Grid, Stack, Typography } from '@mui/material'; 4 | import { DevicesProvider, Canvas as MobileCanvas } from '@grapesjs/react'; 5 | import { Canvas as DesktopCanvas } from '@grapesjs/react'; 6 | import FormControl from '@mui/material/FormControl'; 7 | import MenuItem from '@mui/material/MenuItem'; 8 | import Select from '@mui/material/Select'; 9 | import HeroImage from '../theme/HeroImage'; 10 | 11 | const style = { 12 | button: { 13 | display: 'flex', 14 | 15 | padding: "10px 20px", 16 | width: "30%", 17 | height: "80px", 18 | justifyContent: "center", 19 | alignItems: "center", 20 | flexDirection: "column", 21 | backgroundColor: "#2F3031", 22 | borderRadius: "10px", 23 | fontSize: '14px', 24 | }, 25 | centerWrapper: { 26 | backgroundColor: '#1E1E1E', 27 | display: 'flex', 28 | justifyContent: 'center', 29 | alignItem: 'center', 30 | flexDirection: 'row', 31 | paddingTop: '60px', 32 | paddingButtom: '60px', 33 | 34 | }, 35 | title: { 36 | width: '100%', 37 | height: '35px', 38 | padding: '10px 15px', 39 | backgroundColor: "#2B2B2B", 40 | fontSize: '12px', 41 | borderRadius: '10px', 42 | marginBottom: '15px' 43 | } 44 | } 45 | export default function CenterArea() { 46 | return ( 47 | <> 48 | 49 | 50 | {/* */} 51 | Desktop 52 | 53 | 54 | 55 | 56 | 57 | {/* 58 | Mobile 59 | 60 | 61 | 62 | */} 63 | 64 | 65 | ); 66 | } 67 | -------------------------------------------------------------------------------- /src/components/center/style.css: -------------------------------------------------------------------------------- 1 | .m4yours-editor { 2 | position: absolute; 3 | top: calc(50% - 11px); 4 | left: 26px; 5 | font-weight: 600; 6 | } 7 | .lets-iconsback { 8 | position: relative; 9 | width: 24px; 10 | height: 24px; 11 | overflow: hidden; 12 | flex-shrink: 0; 13 | object-fit: cover; 14 | } 15 | .lets-iconsback-parent { 16 | position: absolute; 17 | top: calc(50% - 12px); 18 | left: 1603px; 19 | display: flex; 20 | flex-direction: row; 21 | align-items: flex-start; 22 | justify-content: flex-start; 23 | gap: 3px; 24 | } 25 | .pheye-bold-icon { 26 | position: absolute; 27 | top: calc(50% - 12px); 28 | left: 1670px; 29 | width: 24px; 30 | height: 24px; 31 | overflow: hidden; 32 | object-fit: cover; 33 | } 34 | .publish { 35 | position: relative; 36 | } 37 | .m4yours-editor-parent, 38 | .publish-wrapper { 39 | position: absolute; 40 | box-sizing: border-box; 41 | height: 48px; 42 | } 43 | .publish-wrapper { 44 | top: calc(50% - 24px); 45 | right: 0; 46 | background-color: #f1614a; 47 | width: 196px; 48 | display: flex; 49 | flex-direction: row; 50 | align-items: center; 51 | justify-content: center; 52 | padding: 10px 20px; 53 | font-size: 13px; 54 | } 55 | .m4yours-editor-parent { 56 | top: 0; 57 | left: calc(50% - 960px); 58 | background-color: #2b2b2b; 59 | border-bottom: 1px solid #575757; 60 | width: 1920px; 61 | overflow: hidden; 62 | font-family: "IBM Plex Sans"; 63 | } 64 | .text { 65 | flex: 1; 66 | position: relative; 67 | line-height: 21px; 68 | background: linear-gradient( 69 | rgba(255, 255, 255, 0.6), 70 | rgba(255, 255, 255, 0.6) 71 | ), 72 | #4b465c; 73 | -webkit-background-clip: text; 74 | -webkit-text-fill-color: transparent; 75 | } 76 | .search-icon { 77 | position: relative; 78 | width: 18px; 79 | height: 18px; 80 | object-fit: cover; 81 | } 82 | .form, 83 | .form1 { 84 | border-radius: 4px; 85 | display: flex; 86 | flex-direction: row; 87 | align-items: center; 88 | justify-content: flex-start; 89 | } 90 | .form1 { 91 | flex: 1; 92 | overflow: hidden; 93 | padding: 6px 10px; 94 | gap: 6px; 95 | } 96 | .form { 97 | position: absolute; 98 | top: 26px; 99 | left: 26px; 100 | background-color: #333; 101 | width: 308px; 102 | font-size: 13px; 103 | } 104 | .frame-child, 105 | .frame-item { 106 | position: absolute; 107 | top: 84.5px; 108 | left: 25.5px; 109 | border-top: 1px solid #575757; 110 | box-sizing: border-box; 111 | width: 309px; 112 | height: 1px; 113 | } 114 | .frame-item { 115 | top: 357.5px; 116 | } 117 | .my-components { 118 | position: relative; 119 | line-height: 21px; 120 | } 121 | .basic-parent, 122 | .my-components-parent { 123 | position: absolute; 124 | top: 111px; 125 | left: 26px; 126 | width: 308px; 127 | display: flex; 128 | flex-direction: row; 129 | align-items: center; 130 | justify-content: space-between; 131 | } 132 | .basic-parent { 133 | top: 384px; 134 | } 135 | .picture-1-icon { 136 | position: relative; 137 | width: 12px; 138 | height: 12px; 139 | object-fit: cover; 140 | } 141 | .picture-1-parent { 142 | align-self: stretch; 143 | flex: 1; 144 | border-radius: 4px; 145 | background-color: #2f3031; 146 | display: flex; 147 | flex-direction: column; 148 | align-items: center; 149 | justify-content: center; 150 | padding: 12px 20px; 151 | gap: 10px; 152 | } 153 | .frame-group { 154 | align-self: stretch; 155 | height: 89px; 156 | flex-direction: row; 157 | gap: 6px; 158 | } 159 | .frame-group, 160 | .frame-parent, 161 | .frame-wrapper { 162 | display: flex; 163 | align-items: flex-start; 164 | justify-content: flex-start; 165 | } 166 | .frame-wrapper { 167 | width: 99px; 168 | height: 89px; 169 | flex-direction: row; 170 | } 171 | .frame-parent { 172 | position: absolute; 173 | top: 148px; 174 | left: 26px; 175 | width: 308px; 176 | flex-direction: column; 177 | gap: 6px; 178 | font-size: 12px; 179 | } 180 | .icon-parkadd-text { 181 | position: relative; 182 | width: 18px; 183 | height: 18px; 184 | overflow: hidden; 185 | flex-shrink: 0; 186 | object-fit: cover; 187 | } 188 | .frame-container { 189 | position: absolute; 190 | top: 421px; 191 | left: 26px; 192 | width: 308px; 193 | display: flex; 194 | flex-direction: column; 195 | align-items: flex-start; 196 | justify-content: flex-start; 197 | gap: 6px; 198 | font-size: 12px; 199 | } 200 | .form-parent { 201 | position: absolute; 202 | bottom: 0; 203 | left: 0; 204 | background-color: #2b2b2b; 205 | width: 360px; 206 | height: 1032px; 207 | overflow: hidden; 208 | } 209 | .block-options-parent { 210 | position: absolute; 211 | top: 26px; 212 | left: 26px; 213 | width: 308px; 214 | display: flex; 215 | flex-direction: row; 216 | align-items: center; 217 | justify-content: space-between; 218 | } 219 | .icon-park-soliddown-one { 220 | position: relative; 221 | width: 12px; 222 | height: 12px; 223 | overflow: hidden; 224 | flex-shrink: 0; 225 | object-fit: cover; 226 | } 227 | .normal-parent { 228 | flex: 1; 229 | border-radius: 3px; 230 | background-color: #595964; 231 | flex-shrink: 0; 232 | display: flex; 233 | flex-direction: row; 234 | align-items: center; 235 | justify-content: space-between; 236 | padding: 4px 6px; 237 | } 238 | .icon { 239 | position: relative; 240 | width: 7.06px; 241 | height: 9.2px; 242 | object-fit: cover; 243 | } 244 | .mdimonitor-off { 245 | border-radius: 3px 0 0 3px; 246 | background-color: #595964; 247 | width: 23px; 248 | overflow: hidden; 249 | flex-shrink: 0; 250 | display: flex; 251 | flex-direction: column; 252 | align-items: center; 253 | justify-content: center; 254 | padding: 6.900006294250488px 5.914290904998779px; 255 | box-sizing: border-box; 256 | } 257 | .frame-wrapper1, 258 | .mdimonitor-off-wrapper { 259 | flex-shrink: 0; 260 | display: flex; 261 | flex-direction: row; 262 | align-items: flex-start; 263 | justify-content: flex-start; 264 | } 265 | .frame-wrapper1 { 266 | border-radius: 3px 0 0 3px; 267 | } 268 | .icon1 { 269 | position: relative; 270 | width: 7.89px; 271 | height: 9.2px; 272 | object-fit: cover; 273 | } 274 | .mdimonitor-off1 { 275 | background-color: #595964; 276 | width: 23px; 277 | overflow: hidden; 278 | flex-shrink: 0; 279 | display: flex; 280 | flex-direction: column; 281 | align-items: center; 282 | justify-content: center; 283 | padding: 6.900006294250488px 5.914290904998779px; 284 | box-sizing: border-box; 285 | } 286 | .icon2, 287 | .icon3 { 288 | position: relative; 289 | width: 7.16px; 290 | height: 9.2px; 291 | object-fit: cover; 292 | } 293 | .icon3 { 294 | width: 11.03px; 295 | } 296 | .mdimonitor-off3 { 297 | border-radius: 0 3px 3px 0; 298 | background-color: #595964; 299 | width: 23px; 300 | overflow: hidden; 301 | flex-shrink: 0; 302 | display: flex; 303 | flex-direction: column; 304 | align-items: center; 305 | justify-content: center; 306 | padding: 6.900006294250488px 5.914290904998779px; 307 | box-sizing: border-box; 308 | } 309 | .frame-parent7 { 310 | flex-shrink: 0; 311 | display: flex; 312 | flex-direction: row; 313 | align-items: flex-start; 314 | justify-content: flex-start; 315 | gap: 1px; 316 | } 317 | .icon4, 318 | .icon5 { 319 | position: relative; 320 | width: 10.51px; 321 | height: 9.2px; 322 | object-fit: cover; 323 | } 324 | .icon5 { 325 | width: 9.36px; 326 | } 327 | .frame-parent6 { 328 | align-self: stretch; 329 | display: flex; 330 | flex-direction: row; 331 | align-items: flex-start; 332 | justify-content: flex-start; 333 | gap: 3px; 334 | } 335 | .icon-park-soliddown-one-wrapper, 336 | .wrapper { 337 | border-radius: 3px; 338 | background-color: #595964; 339 | display: flex; 340 | flex-direction: row; 341 | align-items: center; 342 | box-sizing: border-box; 343 | } 344 | .wrapper { 345 | width: 42px; 346 | flex-shrink: 0; 347 | justify-content: center; 348 | padding: 4px 10px; 349 | } 350 | .icon-park-soliddown-one-wrapper { 351 | width: 78px; 352 | height: 23px; 353 | justify-content: flex-end; 354 | padding: 4px 6px; 355 | } 356 | .icon6 { 357 | position: relative; 358 | width: 11.35px; 359 | height: 9.2px; 360 | object-fit: cover; 361 | } 362 | .mdimonitor-off6 { 363 | flex: 1; 364 | border-radius: 3px 0 0 3px; 365 | background-color: #595964; 366 | overflow: hidden; 367 | display: flex; 368 | flex-direction: column; 369 | align-items: center; 370 | justify-content: center; 371 | padding: 6.900006294250488px 5.914290904998779px; 372 | } 373 | .frame-wrapper7, 374 | .mdimonitor-off-wrapper4 { 375 | flex: 1; 376 | flex-shrink: 0; 377 | display: flex; 378 | flex-direction: row; 379 | align-items: flex-start; 380 | justify-content: flex-start; 381 | } 382 | .frame-wrapper7 { 383 | border-radius: 3px 0 0 3px; 384 | } 385 | .icon7 { 386 | position: relative; 387 | width: 10.93px; 388 | height: 9.2px; 389 | object-fit: cover; 390 | } 391 | .mdimonitor-off7 { 392 | flex: 1; 393 | background-color: #595964; 394 | overflow: hidden; 395 | display: flex; 396 | flex-direction: column; 397 | align-items: center; 398 | justify-content: center; 399 | padding: 6.900006294250488px 5.914290904998779px; 400 | } 401 | .vector-icon { 402 | position: relative; 403 | width: 5.02px; 404 | height: 9.2px; 405 | object-fit: cover; 406 | } 407 | .mdimonitor-off8 { 408 | flex: 1; 409 | border-radius: 0 3px 3px 0; 410 | background-color: #595964; 411 | overflow: hidden; 412 | display: flex; 413 | flex-direction: column; 414 | align-items: center; 415 | justify-content: center; 416 | padding: 6.900006294250488px 5.914290904998779px; 417 | } 418 | .frame-parent10, 419 | .frame-wrapper9 { 420 | flex: 1; 421 | flex-shrink: 0; 422 | display: flex; 423 | flex-direction: row; 424 | align-items: flex-start; 425 | justify-content: flex-start; 426 | } 427 | .frame-wrapper9 { 428 | border-radius: 0 3px 3px 0; 429 | } 430 | .frame-parent10 { 431 | gap: 1px; 432 | } 433 | .group-icon { 434 | position: relative; 435 | width: 9.2px; 436 | height: 9.2px; 437 | object-fit: cover; 438 | } 439 | .frame-parent5, 440 | .integrate-build-publish-and-wrapper { 441 | display: flex; 442 | align-items: flex-start; 443 | justify-content: flex-start; 444 | } 445 | .frame-parent5 { 446 | align-self: stretch; 447 | flex-direction: column; 448 | gap: 3px; 449 | } 450 | .integrate-build-publish-and-wrapper { 451 | flex-direction: row; 452 | padding: 0 16px; 453 | } 454 | .frame-parent4, 455 | .text1 { 456 | position: absolute; 457 | left: 26px; 458 | } 459 | .frame-parent4 { 460 | top: 91px; 461 | border-radius: 4px; 462 | background-color: #2f3031; 463 | border: 1px solid #575757; 464 | box-sizing: border-box; 465 | width: 308px; 466 | height: 172px; 467 | display: flex; 468 | flex-direction: column; 469 | align-items: flex-start; 470 | justify-content: flex-start; 471 | padding: 12px 12px 50px; 472 | gap: 16px; 473 | font-size: 12px; 474 | font-family: Inter; 475 | } 476 | .text1 { 477 | top: 63px; 478 | font-size: 14px; 479 | color: #707070; 480 | } 481 | .vector { 482 | position: relative; 483 | border-radius: 50%; 484 | background-color: #fff; 485 | width: 12px; 486 | height: 12px; 487 | } 488 | .form-switch-button, 489 | .inline-text-editing-parent { 490 | flex-shrink: 0; 491 | display: flex; 492 | flex-direction: row; 493 | align-items: center; 494 | } 495 | .form-switch-button { 496 | border-radius: 100px; 497 | background-color: #f1614a; 498 | width: 30px; 499 | justify-content: flex-end; 500 | padding: 3px; 501 | box-sizing: border-box; 502 | } 503 | .inline-text-editing-parent { 504 | width: 308px; 505 | justify-content: space-between; 506 | } 507 | .allow-rich-text { 508 | margin: 0; 509 | } 510 | .allow-rich-text-container { 511 | position: relative; 512 | font-size: 14px; 513 | line-height: 18px; 514 | color: #707070; 515 | } 516 | .frame-parent12 { 517 | position: absolute; 518 | top: 289px; 519 | left: 26px; 520 | display: flex; 521 | flex-direction: column; 522 | align-items: flex-start; 523 | justify-content: flex-start; 524 | gap: 12px; 525 | } 526 | .frame-parent3 { 527 | position: absolute; 528 | right: 0; 529 | bottom: 0; 530 | background-color: #2b2b2b; 531 | width: 360px; 532 | height: 1032px; 533 | overflow: hidden; 534 | } 535 | .desktop-wrapper, 536 | .mobile-wrapper { 537 | position: absolute; 538 | top: 138px; 539 | left: 537px; 540 | border-radius: 4px; 541 | background-color: #2b2b2b; 542 | width: 594px; 543 | display: flex; 544 | flex-direction: row; 545 | align-items: center; 546 | justify-content: flex-start; 547 | padding: 10px 16px; 548 | box-sizing: border-box; 549 | font-size: 12px; 550 | } 551 | .mobile-wrapper { 552 | left: 1169px; 553 | width: 214px; 554 | } 555 | .plus-icon { 556 | position: relative; 557 | width: 16px; 558 | height: 16px; 559 | object-fit: cover; 560 | } 561 | .text2 { 562 | position: relative; 563 | letter-spacing: 0.43px; 564 | line-height: 16px; 565 | font-weight: 500; 566 | } 567 | .button3 { 568 | flex-shrink: 0; 569 | flex-direction: row; 570 | padding: 6px 14px; 571 | gap: 6px; 572 | } 573 | .button-wrapper, 574 | .button2, 575 | .button3 { 576 | display: flex; 577 | align-items: center; 578 | justify-content: center; 579 | } 580 | .button2 { 581 | border-radius: 4px; 582 | background-color: #1a73e8; 583 | flex-direction: row; 584 | } 585 | .button-wrapper { 586 | position: absolute; 587 | top: 354px; 588 | left: calc(50% - 297px); 589 | background-color: #05080d; 590 | border: 1px solid #5d96ff; 591 | box-sizing: border-box; 592 | width: 594px; 593 | flex-direction: column; 594 | padding: 40px 10px; 595 | font-size: 13px; 596 | } 597 | .ionlogo-xbox-icon, 598 | .lighticon { 599 | position: relative; 600 | object-fit: cover; 601 | } 602 | .ionlogo-xbox-icon { 603 | width: 19.8px; 604 | height: 19.8px; 605 | overflow: hidden; 606 | flex-shrink: 0; 607 | } 608 | .lighticon { 609 | width: 6.6px; 610 | height: 6.6px; 611 | } 612 | .menu, 613 | .pricing { 614 | display: flex; 615 | flex-direction: row; 616 | } 617 | .pricing { 618 | flex-shrink: 0; 619 | align-items: center; 620 | justify-content: center; 621 | gap: 3.3px; 622 | } 623 | .menu { 624 | flex: 1; 625 | align-items: flex-start; 626 | justify-content: flex-start; 627 | gap: 16.5px; 628 | } 629 | .lightbutton, 630 | .lightsearch-box { 631 | border-radius: 12.38px; 632 | height: 19.8px; 633 | overflow: hidden; 634 | display: flex; 635 | align-items: center; 636 | box-sizing: border-box; 637 | } 638 | .lightsearch-box { 639 | background-color: #f0f1f2; 640 | width: 99px; 641 | flex-shrink: 0; 642 | flex-direction: row; 643 | justify-content: flex-start; 644 | padding: 0 0 0 9.074999809265137px; 645 | gap: 4.13px; 646 | } 647 | .lightbutton { 648 | background-color: #4475f2; 649 | flex-direction: column; 650 | justify-content: center; 651 | padding: 0 15.675000190734863px; 652 | color: #fff; 653 | } 654 | .right { 655 | display: flex; 656 | flex-direction: row; 657 | align-items: flex-start; 658 | justify-content: flex-start; 659 | gap: 3.3px; 660 | text-align: center; 661 | font-size: 12px; 662 | font-family: "Plus Jakarta Display"; 663 | } 664 | .container1, 665 | .header-light-04 { 666 | position: absolute; 667 | top: 0; 668 | height: 29.7px; 669 | } 670 | .container1 { 671 | left: 61.88px; 672 | width: 470.25px; 673 | display: flex; 674 | flex-direction: row; 675 | align-items: center; 676 | justify-content: flex-start; 677 | gap: 16.5px; 678 | } 679 | .header-light-04 { 680 | left: calc(50% - 297px); 681 | background-color: #000; 682 | border-bottom: 1px solid #575757; 683 | box-sizing: border-box; 684 | width: 594px; 685 | overflow: hidden; 686 | color: #9a9ea6; 687 | font-family: "IBM Plex Sans"; 688 | } 689 | .bottom-bar { 690 | position: absolute; 691 | top: 135.71px; 692 | left: 61.88px; 693 | width: 470.25px; 694 | display: flex; 695 | flex-direction: row; 696 | align-items: center; 697 | justify-content: space-between; 698 | } 699 | .faq { 700 | position: relative; 701 | text-transform: capitalize; 702 | } 703 | .items, 704 | .menu1, 705 | .menu2 { 706 | display: flex; 707 | flex-direction: column; 708 | align-items: flex-start; 709 | } 710 | .items { 711 | flex-shrink: 0; 712 | justify-content: flex-start; 713 | gap: 8.25px; 714 | font-size: 5.78px; 715 | color: #9a9ea6; 716 | } 717 | .menu1, 718 | .menu2 { 719 | top: 0; 720 | justify-content: center; 721 | gap: 9.9px; 722 | } 723 | .menu1 { 724 | position: absolute; 725 | left: 160.88px; 726 | } 727 | .menu2 { 728 | left: 80.44px; 729 | } 730 | .menu2, 731 | .menu3, 732 | .menus { 733 | position: absolute; 734 | } 735 | .menu3 { 736 | top: 0; 737 | left: 0; 738 | display: flex; 739 | flex-direction: column; 740 | align-items: flex-start; 741 | justify-content: center; 742 | gap: 9.9px; 743 | } 744 | .menus { 745 | top: 23.1px; 746 | left: 303.19px; 747 | width: 208.88px; 748 | height: 92.9px; 749 | font-size: 7.43px; 750 | color: #464646; 751 | } 752 | .logo-icon { 753 | position: relative; 754 | width: 35.71px; 755 | height: 16.5px; 756 | object-fit: cover; 757 | } 758 | .we-ara-a { 759 | line-height: 9.9px; 760 | } 761 | .read-more { 762 | color: #4475f2; 763 | } 764 | .we-ara-a-container { 765 | align-self: stretch; 766 | position: relative; 767 | } 768 | .introduction { 769 | align-self: stretch; 770 | display: flex; 771 | flex-direction: column; 772 | align-items: flex-start; 773 | justify-content: center; 774 | gap: 4.95px; 775 | } 776 | .lightsocial-icons { 777 | position: relative; 778 | width: 8.25px; 779 | height: 8.25px; 780 | object-fit: cover; 781 | } 782 | .lightmini-button { 783 | border-radius: 12.38px; 784 | background-color: #e3ebfd; 785 | width: 19.8px; 786 | height: 19.8px; 787 | overflow: hidden; 788 | flex-shrink: 0; 789 | display: flex; 790 | flex-direction: row; 791 | align-items: center; 792 | justify-content: center; 793 | } 794 | .left, 795 | .socials { 796 | display: flex; 797 | justify-content: flex-start; 798 | } 799 | .socials { 800 | flex-shrink: 0; 801 | flex-direction: row; 802 | align-items: center; 803 | gap: 3.3px; 804 | } 805 | .left { 806 | position: absolute; 807 | top: 23.1px; 808 | left: 61.88px; 809 | flex-direction: column; 810 | align-items: flex-start; 811 | gap: 12.38px; 812 | } 813 | .footer-light-04 { 814 | position: absolute; 815 | bottom: 0; 816 | left: calc(50% - 297px); 817 | background-color: #0c0c0c; 818 | width: 594px; 819 | height: 196px; 820 | overflow: hidden; 821 | color: #9a9ea6; 822 | font-family: "IBM Plex Sans"; 823 | } 824 | .text3 { 825 | position: relative; 826 | letter-spacing: 0.25px; 827 | font-weight: 500; 828 | } 829 | .button4 { 830 | background-color: #1a73e8; 831 | border-right: 0.6px solid rgba(0, 0, 0, 0.1); 832 | flex-shrink: 0; 833 | display: flex; 834 | flex-direction: row; 835 | align-items: center; 836 | justify-content: center; 837 | padding: 5.833333969116211px 11.666667938232422px; 838 | } 839 | .chevron-down-icon3 { 840 | position: relative; 841 | width: 10px; 842 | height: 10px; 843 | object-fit: cover; 844 | } 845 | .button6 { 846 | background-color: #1a73e8; 847 | flex-shrink: 0; 848 | display: flex; 849 | flex-direction: row; 850 | align-items: center; 851 | justify-content: center; 852 | padding: 5.833333969116211px 11.666667938232422px; 853 | } 854 | .horizontal-button-group { 855 | position: absolute; 856 | top: 330px; 857 | left: 18px; 858 | border-radius: 3.5px; 859 | overflow: hidden; 860 | display: flex; 861 | flex-direction: row; 862 | align-items: flex-start; 863 | justify-content: flex-start; 864 | } 865 | .unsplash-hcpwe1-prc-icon { 866 | position: absolute; 867 | top: calc(50% - 242px); 868 | right: -36px; 869 | width: 729px; 870 | height: 485px; 871 | object-fit: cover; 872 | } 873 | .gift-guide, 874 | .heres-to-joy { 875 | position: absolute; 876 | top: 18.95px; 877 | left: calc(50% - 114.5px); 878 | } 879 | .gift-guide { 880 | top: 0; 881 | left: calc(50% - 38.5px); 882 | font-size: 13.41px; 883 | text-transform: uppercase; 884 | font-weight: 600; 885 | color: #69764a; 886 | } 887 | .there-are-many { 888 | position: absolute; 889 | top: 69.67px; 890 | left: 0; 891 | font-size: 8.57px; 892 | color: #7a8365; 893 | text-align: center; 894 | display: inline-block; 895 | width: 299px; 896 | } 897 | .plus-icon1 { 898 | position: relative; 899 | width: 16px; 900 | height: 16px; 901 | object-fit: cover; 902 | display: none; 903 | } 904 | .text5 { 905 | position: relative; 906 | letter-spacing: 0.43px; 907 | line-height: 16px; 908 | text-transform: uppercase; 909 | font-weight: 500; 910 | } 911 | .button7 { 912 | position: absolute; 913 | top: 105.95px; 914 | left: calc(50% - 55.5px); 915 | border-radius: 4px; 916 | background-color: #536136; 917 | display: flex; 918 | flex-direction: row; 919 | align-items: center; 920 | justify-content: center; 921 | font-size: 13px; 922 | color: #fff; 923 | font-family: "Public Sans"; 924 | } 925 | .heres-to-joy-parent { 926 | position: absolute; 927 | top: 95px; 928 | left: calc(50% - 149px); 929 | width: 299px; 930 | height: 133.95px; 931 | } 932 | .unsplash-hcpwe1-prc-parent { 933 | position: absolute; 934 | top: 0; 935 | left: 0; 936 | background-color: #fff; 937 | width: 594px; 938 | height: 324px; 939 | overflow: hidden; 940 | text-align: left; 941 | font-size: 36.22px; 942 | color: #536136; 943 | font-family: Inter; 944 | } 945 | .group-child { 946 | position: absolute; 947 | top: 312px; 948 | left: 552px; 949 | width: 24px; 950 | height: 24px; 951 | object-fit: cover; 952 | } 953 | .horizontal-button-group-parent { 954 | position: absolute; 955 | top: 30px; 956 | left: 0; 957 | width: 594px; 958 | height: 351.67px; 959 | text-align: center; 960 | font-size: 8.75px; 961 | } 962 | .frame-parent13 { 963 | position: absolute; 964 | top: 193px; 965 | left: 537px; 966 | background-color: #000; 967 | width: 594px; 968 | height: 805px; 969 | overflow: hidden; 970 | font-size: 5.78px; 971 | } 972 | .ionlogo-xbox-icon1 { 973 | position: absolute; 974 | top: calc(50% - 8px); 975 | left: 16px; 976 | width: 16px; 977 | height: 16px; 978 | overflow: hidden; 979 | object-fit: cover; 980 | } 981 | .darkmini-button { 982 | position: absolute; 983 | top: calc(50% - 9px); 984 | right: 16px; 985 | width: 18px; 986 | height: 18px; 987 | overflow: hidden; 988 | display: flex; 989 | flex-direction: row; 990 | align-items: center; 991 | justify-content: center; 992 | } 993 | .ionlogo-xbox-parent { 994 | position: absolute; 995 | top: 0; 996 | left: 0; 997 | background-color: #000; 998 | border-bottom: 1px solid #575757; 999 | box-sizing: border-box; 1000 | width: 214px; 1001 | height: 30px; 1002 | overflow: hidden; 1003 | } 1004 | .logo-child, 1005 | .swipe-icon { 1006 | position: absolute; 1007 | height: 34.93%; 1008 | width: 45.31%; 1009 | top: 35.53%; 1010 | right: 0; 1011 | bottom: 29.53%; 1012 | left: 54.69%; 1013 | max-width: 100%; 1014 | overflow: hidden; 1015 | max-height: 100%; 1016 | object-fit: cover; 1017 | } 1018 | .logo-child { 1019 | height: 100%; 1020 | width: 46.2%; 1021 | top: 0; 1022 | right: 53.8%; 1023 | bottom: 0; 1024 | left: 0; 1025 | } 1026 | .logo { 1027 | position: absolute; 1028 | height: 12.42%; 1029 | width: 29.91%; 1030 | top: 6.92%; 1031 | right: 62.62%; 1032 | bottom: 80.66%; 1033 | left: 7.48%; 1034 | } 1035 | .we-ara-a-container1 { 1036 | position: absolute; 1037 | top: 56.03px; 1038 | left: 16px; 1039 | display: inline-block; 1040 | width: 182px; 1041 | } 1042 | .socials1 { 1043 | position: absolute; 1044 | top: 178px; 1045 | left: 51px; 1046 | display: flex; 1047 | flex-direction: row; 1048 | align-items: center; 1049 | justify-content: flex-start; 1050 | gap: 3.3px; 1051 | } 1052 | .all-rights-reserved1 { 1053 | position: absolute; 1054 | top: 214px; 1055 | left: calc(50% - 44px); 1056 | } 1057 | .about-parent, 1058 | .frame-parent15 { 1059 | display: flex; 1060 | align-items: flex-start; 1061 | } 1062 | .about-parent { 1063 | width: 182px; 1064 | flex-shrink: 0; 1065 | flex-direction: row; 1066 | justify-content: space-between; 1067 | } 1068 | .frame-parent15 { 1069 | position: absolute; 1070 | top: 110px; 1071 | left: 16px; 1072 | flex-direction: column; 1073 | justify-content: flex-start; 1074 | gap: 10px; 1075 | font-size: 7.43px; 1076 | color: #464646; 1077 | } 1078 | .logo-parent { 1079 | position: absolute; 1080 | bottom: 0; 1081 | left: calc(50% - 107px); 1082 | background-color: #0c0c0c; 1083 | width: 214px; 1084 | height: 238px; 1085 | overflow: hidden; 1086 | } 1087 | .unsplash-hcpwe1-prc-icon1 { 1088 | position: absolute; 1089 | top: calc(50% - 110.5px); 1090 | left: calc(50% - 182px); 1091 | width: 333px; 1092 | height: 221px; 1093 | object-fit: cover; 1094 | } 1095 | .gift-guide1, 1096 | .heres-to-joy1 { 1097 | position: absolute; 1098 | top: 9.82px; 1099 | left: calc(50% - 59.36px); 1100 | } 1101 | .gift-guide1 { 1102 | top: 0; 1103 | left: calc(50% - 19.96px); 1104 | font-size: 6.95px; 1105 | text-transform: uppercase; 1106 | font-weight: 600; 1107 | color: #69764a; 1108 | } 1109 | .there-are-many1 { 1110 | position: absolute; 1111 | top: 36.12px; 1112 | left: 0; 1113 | font-size: 4.44px; 1114 | color: #7a8365; 1115 | text-align: center; 1116 | display: inline-block; 1117 | width: 155px; 1118 | } 1119 | .plus-icon2 { 1120 | position: relative; 1121 | width: 8.29px; 1122 | height: 8.29px; 1123 | object-fit: cover; 1124 | display: none; 1125 | } 1126 | .text6 { 1127 | position: relative; 1128 | letter-spacing: 0.22px; 1129 | line-height: 8.29px; 1130 | text-transform: uppercase; 1131 | font-weight: 500; 1132 | } 1133 | .button10, 1134 | .button9 { 1135 | display: flex; 1136 | flex-direction: row; 1137 | align-items: center; 1138 | justify-content: center; 1139 | } 1140 | .button10 { 1141 | padding: 3.110367774963379px 7.2575249671936035px; 1142 | gap: 3.11px; 1143 | } 1144 | .button9 { 1145 | position: absolute; 1146 | top: 54.92px; 1147 | left: calc(50% - 28.61px); 1148 | border-radius: 2.07px; 1149 | background-color: #536136; 1150 | width: 48.73px; 1151 | height: 14.52px; 1152 | font-size: 6.74px; 1153 | color: #fff; 1154 | font-family: "Public Sans"; 1155 | } 1156 | .heres-to-joy-group { 1157 | position: absolute; 1158 | top: 52px; 1159 | left: calc(50% - 78px); 1160 | width: 155px; 1161 | height: 69.44px; 1162 | } 1163 | .unsplash-hcpwe1-prc-group { 1164 | position: absolute; 1165 | top: 0; 1166 | left: 0; 1167 | background-color: #fff; 1168 | width: 214px; 1169 | height: 173px; 1170 | overflow: hidden; 1171 | } 1172 | .button-container, 1173 | .button11 { 1174 | display: flex; 1175 | align-items: center; 1176 | justify-content: center; 1177 | } 1178 | .button11 { 1179 | border-radius: 4px; 1180 | background-color: #5d96ff; 1181 | flex-direction: row; 1182 | } 1183 | .button-container { 1184 | position: absolute; 1185 | top: 173px; 1186 | left: calc(50% - 107px); 1187 | background-color: #05080d; 1188 | border: 1px solid #5d96ff; 1189 | box-sizing: border-box; 1190 | width: 214px; 1191 | flex-direction: column; 1192 | padding: 40px 10px; 1193 | font-size: 13px; 1194 | color: #fff; 1195 | font-family: "Public Sans"; 1196 | } 1197 | .frame-parent14, 1198 | .group-div { 1199 | position: absolute; 1200 | top: 30px; 1201 | left: 0; 1202 | width: 214px; 1203 | height: 281px; 1204 | font-size: 18.78px; 1205 | color: #536136; 1206 | font-family: Inter; 1207 | } 1208 | .frame-parent14 { 1209 | top: 193px; 1210 | left: 1169px; 1211 | background-color: #000; 1212 | height: 724px; 1213 | overflow: hidden; 1214 | font-size: 5.78px; 1215 | color: #9a9ea6; 1216 | font-family: "IBM Plex Sans"; 1217 | } 1218 | .editor { 1219 | position: relative; 1220 | background-color: #1e1e1e; 1221 | width: 100%; 1222 | height: 1080px; 1223 | overflow: hidden; 1224 | text-align: left; 1225 | font-size: 16px; 1226 | color: #fff; 1227 | font-family: "Public Sans"; 1228 | } 1229 | -------------------------------------------------------------------------------- /src/components/common.ts: -------------------------------------------------------------------------------- 1 | export const MAIN_BG_COLOR = 'bg-slate-900'; 2 | 3 | export const MAIN_TXT_COLOR = 'text-white'; 4 | 5 | export const BTN_CLS = 'border rounded px-2 py-1 w-full'; 6 | 7 | export const BTN_TOP_CLS = 'px-2 py-1 w-full text-white'; 8 | 9 | export const MAIN_BORDER_COLOR = 'border-slate-500'; 10 | 11 | export const ROUND_BORDER_COLOR = `rounded border ${MAIN_BORDER_COLOR}`; 12 | 13 | export function cx(...inputs: any[]): string { 14 | const inp = Array.isArray(inputs[0]) ? inputs[0] : [...inputs]; 15 | return inp.filter(Boolean).join(' '); 16 | } 17 | -------------------------------------------------------------------------------- /src/components/headers/Topbar.tsx: -------------------------------------------------------------------------------- 1 | import * as React from 'react'; 2 | import { DevicesProvider, WithEditor } from '@grapesjs/react'; 3 | import FormControl from '@mui/material/FormControl'; 4 | import MenuItem from '@mui/material/MenuItem'; 5 | import Select from '@mui/material/Select'; 6 | import { cx } from '../common'; 7 | import TopbarButtons from './TopbarButtons'; 8 | import { Button, Typography } from '@mui/material'; 9 | import Link from 'next/link'; 10 | 11 | export default function Topbar({ 12 | className, 13 | }: React.HTMLAttributes) { 14 | return ( 15 |
16 | 17 | M4yours Editor 18 | 19 | 20 | {({ selected, select, devices }) => ( 21 | 22 | 29 | 30 | )} 31 | 32 | 33 | 34 | 35 | 36 |
37 | ); 38 | } 39 | -------------------------------------------------------------------------------- /src/components/headers/TopbarButtons.tsx: -------------------------------------------------------------------------------- 1 | import * as React from 'react'; 2 | import { useEditor } from '@grapesjs/react'; 3 | import { 4 | mdiArrowULeftTop, 5 | mdiArrowURightTop, 6 | mdiBorderRadius, 7 | mdiFullscreen, 8 | mdiXml, 9 | mdiEyeOutline 10 | } from '@mdi/js'; 11 | import Icon from '@mdi/react'; 12 | import { useEffect, useState } from 'react'; 13 | import { BTN_CLS, MAIN_BORDER_COLOR, cx, BTN_TOP_CLS } from '../common'; 14 | 15 | interface CommandButton { 16 | id: string; 17 | iconPath: string; 18 | options?: Record; 19 | disabled?: () => boolean; 20 | } 21 | 22 | export default function TopbarButtons({ 23 | className, 24 | }: React.HTMLAttributes) { 25 | const editor = useEditor(); 26 | const [, setUpdateCounter] = useState(0); 27 | const { UndoManager, Commands } = editor; 28 | const cmdButtons: CommandButton[] = [ 29 | // { 30 | // id: 'core:component-outline', 31 | // iconPath: mdiBorderRadius, 32 | // }, 33 | // { 34 | // id: 'core:fullscreen', 35 | // iconPath: mdiFullscreen, 36 | // options: { target: '#root' }, 37 | // }, 38 | // { 39 | // id: 'core:open-code', 40 | // iconPath: mdiXml, 41 | // }, 42 | { 43 | id: 'core:undo', 44 | iconPath: mdiArrowULeftTop, 45 | disabled: () => !UndoManager.hasUndo(), 46 | }, 47 | { 48 | id: 'core:redo', 49 | iconPath: mdiArrowURightTop, 50 | disabled: () => !UndoManager.hasRedo(), 51 | }, 52 | { 53 | id: 'core:preview', 54 | iconPath: mdiEyeOutline , 55 | }, 56 | ]; 57 | 58 | useEffect(() => { 59 | const cmdEvent = 'run stop'; 60 | const updateEvent = 'update'; 61 | const updateCounter = () => setUpdateCounter((value) => value + 1); 62 | const onCommand = (id: string) => { 63 | cmdButtons.find((btn) => btn.id === id) && updateCounter(); 64 | }; 65 | editor.on(cmdEvent, onCommand); 66 | editor.on(updateEvent, updateCounter); 67 | 68 | return () => { 69 | editor.off(cmdEvent, onCommand); 70 | editor.off(updateEvent, updateCounter); 71 | }; 72 | }, []); 73 | 74 | return ( 75 |
76 | {cmdButtons.map(({ id, iconPath, disabled, options = {} }) => ( 77 | 95 | ))} 96 |
97 | ); 98 | } 99 | -------------------------------------------------------------------------------- /src/components/home/index.tsx: -------------------------------------------------------------------------------- 1 | import type { NextPage } from "next"; 2 | import Link from "next/link"; 3 | 4 | const HomeCom: NextPage = () => { 5 | return ( 6 |
7 |
8 |
9 |
10 |
11 |
12 |
IN Progress
13 |
14 |
15 |
Front-end Task
16 |
17 |
18 |
19 |
20 | M4yours Editor 21 |
22 | 23 | 28 | 29 |
30 |
31 |
{`Drag and Drop `}
32 |
33 | ); 34 | }; 35 | 36 | export default HomeCom; 37 | -------------------------------------------------------------------------------- /src/components/leftBlock/CustomBlockManager.tsx: -------------------------------------------------------------------------------- 1 | import * as React from 'react'; 2 | import { BlocksResultProps } from '@grapesjs/react'; 3 | import { MAIN_BORDER_COLOR, cx } from '../common'; 4 | import { Box, Typography } from '@mui/material'; 5 | 6 | 7 | const style = { 8 | button: { 9 | display: 'flex', 10 | padding: "10px 5px", 11 | width: "auto", 12 | height: "80px", 13 | justifyContent: "center", 14 | alignItems: "center", 15 | flexDirection: "column", 16 | backgroundColor: "#2F3031", 17 | borderRadius: "10px", 18 | fontSize: '14px', 19 | } 20 | } 21 | export type CustomBlockManagerProps = Pick< 22 | BlocksResultProps, 23 | 'mapCategoryBlocks' | 'dragStart' | 'dragStop' 24 | >; 25 | export default function CustomBlockManager({ 26 | mapCategoryBlocks, 27 | dragStart, 28 | dragStop, 29 | }: CustomBlockManagerProps) { 30 | console.log('Block', mapCategoryBlocks) 31 | return ( 32 |
33 | {Array.from(mapCategoryBlocks).map(([category, blocks]) => ( 34 |
35 |
36 | {category} 37 |
38 |
39 | {blocks.map((block) => ( 40 | dragStart(block, ev.nativeEvent)} 49 | onDragEnd={() => dragStop(false)} 50 | > 51 |
55 | 59 | {block.getLabel()} 60 | 61 | 62 | ))} 63 |
64 |
65 | ))} 66 |
67 | ); 68 | } 69 | -------------------------------------------------------------------------------- /src/components/leftBlock/MyBlockManager.tsx: -------------------------------------------------------------------------------- 1 | import * as React from 'react'; 2 | import { BlocksResultProps } from '@grapesjs/react'; 3 | import { MAIN_BORDER_COLOR, cx } from '../common'; 4 | import { Box, Typography } from '@mui/material'; 5 | 6 | 7 | const style = { 8 | button: { 9 | display: 'flex', 10 | padding: "10px 20px", 11 | width: "auto", 12 | height: "80px", 13 | justifyContent: "center", 14 | alignItems: "center", 15 | flexDirection: "column", 16 | backgroundColor: "#2F3031", 17 | borderRadius: "10px", 18 | fontSize: '14px', 19 | } 20 | } 21 | export type MyBlockManagerProps = Pick< 22 | BlocksResultProps, 23 | 'mapCategoryBlocks' | 'dragStart' | 'dragStop' 24 | >; 25 | export default function MyBlockManagerProps({ 26 | mapCategoryBlocks, 27 | dragStart, 28 | dragStop, 29 | }: MyBlockManagerProps) { 30 | console.log('Block', mapCategoryBlocks) 31 | return ( 32 |
33 | {Array.from(mapCategoryBlocks).map(([category, blocks]) => ( 34 |
35 |
36 | My Component 37 |
38 |
39 | {blocks.map((block) => ( 40 | dragStart(block, ev.nativeEvent)} 49 | onDragEnd={() => dragStop(false)} 50 | > 51 |
55 | 59 | {block.getLabel()} 60 | 61 | 62 | ))} 63 |
64 |
65 | ))} 66 |
67 | ); 68 | } 69 | -------------------------------------------------------------------------------- /src/components/leftBlock/index.tsx: -------------------------------------------------------------------------------- 1 | import * as React from 'react'; 2 | import { BlocksResultProps, BlocksProvider } from '@grapesjs/react'; 3 | import { MAIN_BORDER_COLOR, cx } from '../common'; 4 | import { FunctionComponent } from "react"; 5 | import styles from "./leftblock.module.css"; 6 | import { Box, Grid, Stack, Typography } from '@mui/material'; 7 | import CustomBlockManager from './CustomBlockManager'; 8 | import MyBlockManager from './MyBlockManager'; 9 | 10 | const style = { 11 | button: { 12 | display: 'flex', 13 | 14 | padding: "10px 20px", 15 | width: "30%", 16 | height: "80px", 17 | justifyContent: "center", 18 | alignItems: "center", 19 | flexDirection: "column", 20 | backgroundColor: "#2F3031", 21 | borderRadius: "10px", 22 | fontSize: '14px', 23 | } 24 | } 25 | export default function LeftBlock() { 26 | return ( 27 | <> 28 | 29 | 30 | 31 | {(props) => } 32 | 33 | 34 | 35 | 36 | ); 37 | } 38 | -------------------------------------------------------------------------------- /src/components/theme/CustomButton.tsx: -------------------------------------------------------------------------------- 1 | // components/CustomButton.js 2 | import React from 'react'; 3 | 4 | const CustomButton = ({ text} : any) => { 5 | return ( 6 | 9 | ); 10 | }; 11 | 12 | export default CustomButton; 13 | -------------------------------------------------------------------------------- /src/components/theme/HeroImage.tsx: -------------------------------------------------------------------------------- 1 | import * as React from 'react'; 2 | import { BlocksResultProps, BlocksProvider } from '@grapesjs/react'; 3 | import { MAIN_BORDER_COLOR, cx } from '../common'; 4 | import { FunctionComponent } from "react"; 5 | import styles from "./leftblock.module.css"; 6 | import { Box, Grid, Stack, Typography } from '@mui/material'; 7 | 8 | export default function HeroImage() { 9 | return ( 10 | <> 11 |
12 | 13 |
14 |
15 | 20 |
21 |
Services
22 |
23 |
Pricing
24 | 29 |
30 |
Portfolio
31 |
Contact us
32 |
About us
33 |
34 |
35 |
36 | 41 |
Search...
42 |
43 |
44 | Register / Login 45 |
46 |
47 |
48 |
49 |
50 |
51 |
52 | © 2000-2021, All Rights Reserved 53 |
54 |
55 |
56 |
57 | FAQ 58 |
59 |
Account
60 |
Manage Deliveries
61 |
Orders
62 |
Payments
63 |
Returns
64 |
65 |
66 |
67 | Support 68 |
69 |
Contact us
70 |
Online Chat
71 |
Whatsapp
72 |
Telegram
73 |
Ticketing
74 |
75 |
76 |
77 | About 78 |
79 |
About us
80 |
Blog
81 |
Careers
82 |
Jobs
83 |
In Press
84 |
85 |
86 |
87 |
88 |
89 | 90 |
91 | {`We ara a lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat... `} 94 | Read More 95 |
96 |
97 |
98 |
99 | 104 |
105 |
106 | 111 |
112 |
113 | 118 |
119 |
120 | 125 |
126 |
127 | 132 |
133 |
134 |
135 |
136 |
137 | 138 | ); 139 | } 140 | -------------------------------------------------------------------------------- /src/components/theme/leftblock.module.css: -------------------------------------------------------------------------------- 1 | .m4yoursEditor { 2 | position: absolute; 3 | top: calc(50% - 11px); 4 | left: 26px; 5 | font-weight: 600; 6 | } 7 | .letsIconsback2 { 8 | position: relative; 9 | width: 24px; 10 | height: 24px; 11 | overflow: hidden; 12 | flex-shrink: 0; 13 | object-fit: cover; 14 | } 15 | .letsIconsbackParent, 16 | .pheyeBoldIcon1 { 17 | position: absolute; 18 | top: calc(50% - 12px); 19 | } 20 | .letsIconsbackParent { 21 | left: 1603px; 22 | display: flex; 23 | flex-direction: row; 24 | align-items: flex-start; 25 | justify-content: flex-start; 26 | gap: 3px; 27 | } 28 | .pheyeBoldIcon1 { 29 | left: 1670px; 30 | width: 24px; 31 | height: 24px; 32 | overflow: hidden; 33 | object-fit: cover; 34 | } 35 | .publish { 36 | position: relative; 37 | } 38 | .m4yoursEditorParent, 39 | .publishWrapper { 40 | position: absolute; 41 | box-sizing: border-box; 42 | height: 48px; 43 | } 44 | .publishWrapper { 45 | top: calc(50% - 24px); 46 | right: 0; 47 | background-color: #f1614a; 48 | width: 196px; 49 | display: flex; 50 | flex-direction: row; 51 | align-items: center; 52 | justify-content: center; 53 | padding: 10px 20px; 54 | font-size: 13px; 55 | } 56 | .m4yoursEditorParent { 57 | top: 0; 58 | left: calc(50% - 960px); 59 | background-color: #2b2b2b; 60 | border-bottom: 1px solid #575757; 61 | width: 1920px; 62 | overflow: hidden; 63 | font-family: "IBM Plex Sans"; 64 | } 65 | .text9 { 66 | flex: 1; 67 | position: relative; 68 | line-height: 21px; 69 | background: linear-gradient( 70 | rgba(255, 255, 255, 0.6), 71 | rgba(255, 255, 255, 0.6) 72 | ), 73 | #4b465c; 74 | -webkit-background-clip: text; 75 | -webkit-text-fill-color: transparent; 76 | } 77 | .form, 78 | .form1 { 79 | border-radius: 4px; 80 | display: flex; 81 | flex-direction: row; 82 | align-items: center; 83 | justify-content: flex-start; 84 | } 85 | .form1 { 86 | flex: 1; 87 | overflow: hidden; 88 | padding: 6px 10px; 89 | gap: 6px; 90 | } 91 | .form { 92 | /* position: absolute; */ 93 | top: 26px; 94 | left: 26px; 95 | background-color: #333; 96 | width: auto; 97 | font-size: 13px; 98 | } 99 | .frameChild, 100 | .frameItem { 101 | /* position: absolute; */ 102 | top: 84.5px; 103 | left: 25.5px; 104 | border-top: 1px solid #575757; 105 | box-sizing: border-box; 106 | /* width: 309px; */ 107 | height: 1px; 108 | } 109 | .frameItem { 110 | top: 357.5px; 111 | } 112 | .myComponents { 113 | position: relative; 114 | line-height: 21px; 115 | margin-bottom: 10px; 116 | } 117 | .basicParent, 118 | .myComponentsParent { 119 | /* position: absolute; */ 120 | top: 111px; 121 | left: 26px; 122 | /* width: 308px; */ 123 | display: flex; 124 | flex-direction: row; 125 | align-items: center; 126 | justify-content: space-between; 127 | } 128 | .basicParent { 129 | top: 384px; 130 | } 131 | .picture1Icon4 { 132 | position: relative; 133 | width: 12px; 134 | height: 12px; 135 | object-fit: cover; 136 | } 137 | .picture1Parent { 138 | align-self: stretch; 139 | /* flex: 1; */ 140 | border-radius: 4px; 141 | background-color: #2f3031; 142 | display: flex; 143 | flex-direction: column; 144 | align-items: center; 145 | justify-content: center; 146 | padding: 12px 20px; 147 | gap: 10px; 148 | width: 30%; 149 | flex-flow: wrap; 150 | } 151 | .frameGroup { 152 | align-self: stretch; 153 | /* height: 89px; */ 154 | flex-direction: row; 155 | gap: 6px; 156 | flex-flow: wrap; 157 | margin-bottom: 15px; 158 | } 159 | .frameGroup, 160 | .frameParent, 161 | .frameWrapper { 162 | display: flex; 163 | align-items: flex-start; 164 | justify-content: flex-start; 165 | } 166 | .frameWrapper { 167 | width: 99px; 168 | /* height: 89px; */ 169 | flex-direction: row; 170 | } 171 | .frameParent { 172 | /* position: absolute; */ 173 | top: 148px; 174 | left: 26px; 175 | /* width: 308px; */ 176 | flex-direction: column; 177 | gap: 6px; 178 | font-size: 12px; 179 | } 180 | .iconParkaddText1 { 181 | position: relative; 182 | width: 18px; 183 | height: 18px; 184 | overflow: hidden; 185 | flex-shrink: 0; 186 | object-fit: cover; 187 | } 188 | .frameParent1 { 189 | /* position: absolute; */ 190 | top: 421px; 191 | left: 26px; 192 | /* width: 308px; */ 193 | display: flex; 194 | flex-direction: column; 195 | align-items: flex-start; 196 | justify-content: flex-start; 197 | gap: 6px; 198 | font-size: 12px; 199 | } 200 | .formParent { 201 | bottom: 0; 202 | padding-top: 20px; 203 | background-color: #2b2b2b; 204 | height: 100vh; 205 | overflow: hidden; 206 | } 207 | .blockOptionsParent { 208 | position: absolute; 209 | top: 26px; 210 | left: 26px; 211 | width: 308px; 212 | display: flex; 213 | flex-direction: row; 214 | align-items: center; 215 | justify-content: space-between; 216 | } 217 | .iconParkSoliddownOne2 { 218 | position: relative; 219 | width: 12px; 220 | height: 12px; 221 | overflow: hidden; 222 | flex-shrink: 0; 223 | object-fit: cover; 224 | } 225 | .normalParent { 226 | flex: 1; 227 | border-radius: 3px; 228 | background-color: #595964; 229 | flex-shrink: 0; 230 | display: flex; 231 | flex-direction: row; 232 | align-items: center; 233 | justify-content: space-between; 234 | padding: 4px 6px; 235 | } 236 | .icon9 { 237 | position: relative; 238 | width: 7.06px; 239 | height: 9.2px; 240 | object-fit: cover; 241 | } 242 | .mdimonitorOff { 243 | border-radius: 3px 0 0 3px; 244 | background-color: #595964; 245 | width: 23px; 246 | overflow: hidden; 247 | flex-shrink: 0; 248 | display: flex; 249 | flex-direction: column; 250 | align-items: center; 251 | justify-content: center; 252 | padding: 6.900006294250488px 5.914290904998779px; 253 | box-sizing: border-box; 254 | } 255 | .frameWrapper1, 256 | .mdimonitorOffWrapper { 257 | flex-shrink: 0; 258 | display: flex; 259 | flex-direction: row; 260 | align-items: flex-start; 261 | justify-content: flex-start; 262 | } 263 | .frameWrapper1 { 264 | border-radius: 3px 0 0 3px; 265 | } 266 | .icon10 { 267 | position: relative; 268 | width: 7.89px; 269 | height: 9.2px; 270 | object-fit: cover; 271 | } 272 | .mdimonitorOff1 { 273 | background-color: #595964; 274 | width: 23px; 275 | overflow: hidden; 276 | flex-shrink: 0; 277 | display: flex; 278 | flex-direction: column; 279 | align-items: center; 280 | justify-content: center; 281 | padding: 6.900006294250488px 5.914290904998779px; 282 | box-sizing: border-box; 283 | } 284 | .icon11, 285 | .icon12 { 286 | position: relative; 287 | width: 7.16px; 288 | height: 9.2px; 289 | object-fit: cover; 290 | } 291 | .icon12 { 292 | width: 11.03px; 293 | } 294 | .mdimonitorOff3 { 295 | border-radius: 0 3px 3px 0; 296 | background-color: #595964; 297 | width: 23px; 298 | overflow: hidden; 299 | flex-shrink: 0; 300 | display: flex; 301 | flex-direction: column; 302 | align-items: center; 303 | justify-content: center; 304 | padding: 6.900006294250488px 5.914290904998779px; 305 | box-sizing: border-box; 306 | } 307 | .frameParent8 { 308 | flex-shrink: 0; 309 | display: flex; 310 | flex-direction: row; 311 | align-items: flex-start; 312 | justify-content: flex-start; 313 | gap: 1px; 314 | } 315 | .icon13, 316 | .icon14 { 317 | position: relative; 318 | width: 10.51px; 319 | height: 9.2px; 320 | object-fit: cover; 321 | } 322 | .icon14 { 323 | width: 9.36px; 324 | } 325 | .frameParent7 { 326 | align-self: stretch; 327 | display: flex; 328 | flex-direction: row; 329 | align-items: flex-start; 330 | justify-content: flex-start; 331 | gap: 3px; 332 | } 333 | .iconParkSoliddownOneWrapper, 334 | .wrapper { 335 | border-radius: 3px; 336 | background-color: #595964; 337 | display: flex; 338 | flex-direction: row; 339 | align-items: center; 340 | box-sizing: border-box; 341 | } 342 | .wrapper { 343 | width: 42px; 344 | flex-shrink: 0; 345 | justify-content: center; 346 | padding: 4px 10px; 347 | } 348 | .iconParkSoliddownOneWrapper { 349 | width: 78px; 350 | height: 23px; 351 | justify-content: flex-end; 352 | padding: 4px 6px; 353 | } 354 | .icon15 { 355 | position: relative; 356 | width: 11.35px; 357 | height: 9.2px; 358 | object-fit: cover; 359 | } 360 | .mdimonitorOff6 { 361 | flex: 1; 362 | border-radius: 3px 0 0 3px; 363 | background-color: #595964; 364 | overflow: hidden; 365 | display: flex; 366 | flex-direction: column; 367 | align-items: center; 368 | justify-content: center; 369 | padding: 6.900006294250488px 5.914290904998779px; 370 | } 371 | .frameWrapper7, 372 | .mdimonitorOffWrapper5 { 373 | flex: 1; 374 | flex-shrink: 0; 375 | display: flex; 376 | flex-direction: row; 377 | align-items: flex-start; 378 | justify-content: flex-start; 379 | } 380 | .frameWrapper7 { 381 | border-radius: 3px 0 0 3px; 382 | } 383 | .icon16 { 384 | position: relative; 385 | width: 10.93px; 386 | height: 9.2px; 387 | object-fit: cover; 388 | } 389 | .mdimonitorOff7 { 390 | flex: 1; 391 | background-color: #595964; 392 | overflow: hidden; 393 | display: flex; 394 | flex-direction: column; 395 | align-items: center; 396 | justify-content: center; 397 | padding: 6.900006294250488px 5.914290904998779px; 398 | } 399 | .vectorIcon1 { 400 | position: relative; 401 | width: 5.02px; 402 | height: 9.2px; 403 | object-fit: cover; 404 | } 405 | .mdimonitorOff8 { 406 | flex: 1; 407 | border-radius: 0 3px 3px 0; 408 | background-color: #595964; 409 | overflow: hidden; 410 | display: flex; 411 | flex-direction: column; 412 | align-items: center; 413 | justify-content: center; 414 | padding: 6.900006294250488px 5.914290904998779px; 415 | } 416 | .frameParent11, 417 | .frameWrapper9 { 418 | flex: 1; 419 | flex-shrink: 0; 420 | display: flex; 421 | flex-direction: row; 422 | align-items: flex-start; 423 | justify-content: flex-start; 424 | } 425 | .frameWrapper9 { 426 | border-radius: 0 3px 3px 0; 427 | } 428 | .frameParent11 { 429 | gap: 1px; 430 | } 431 | .icon17 { 432 | position: relative; 433 | width: 9.2px; 434 | height: 9.2px; 435 | object-fit: cover; 436 | } 437 | .frameParent6, 438 | .integrateBuildPublishAndWrapper { 439 | display: flex; 440 | align-items: flex-start; 441 | justify-content: flex-start; 442 | } 443 | .frameParent6 { 444 | align-self: stretch; 445 | flex-direction: column; 446 | gap: 3px; 447 | } 448 | .integrateBuildPublishAndWrapper { 449 | flex-direction: row; 450 | padding: 0 16px; 451 | } 452 | .frameParent5, 453 | .text10 { 454 | position: absolute; 455 | left: 26px; 456 | } 457 | .frameParent5 { 458 | top: 91px; 459 | border-radius: 4px; 460 | background-color: #2f3031; 461 | border: 1px solid #575757; 462 | box-sizing: border-box; 463 | width: 308px; 464 | height: 172px; 465 | display: flex; 466 | flex-direction: column; 467 | align-items: flex-start; 468 | justify-content: flex-start; 469 | padding: 12px 12px 50px; 470 | gap: 16px; 471 | font-size: 12px; 472 | font-family: Inter; 473 | } 474 | .text10 { 475 | top: 63px; 476 | font-size: 14px; 477 | color: #707070; 478 | } 479 | .vector1 { 480 | position: relative; 481 | border-radius: 50%; 482 | background-color: #fff; 483 | width: 12px; 484 | height: 12px; 485 | } 486 | .formSwitchButton1, 487 | .inlineTextEditingParent { 488 | flex-shrink: 0; 489 | display: flex; 490 | flex-direction: row; 491 | align-items: center; 492 | } 493 | .formSwitchButton1 { 494 | border-radius: 100px; 495 | background-color: #f1614a; 496 | width: 30px; 497 | justify-content: flex-end; 498 | padding: 3px; 499 | box-sizing: border-box; 500 | } 501 | .inlineTextEditingParent { 502 | width: 308px; 503 | justify-content: space-between; 504 | } 505 | .byDoubleClicking { 506 | margin: 0; 507 | } 508 | .allowRichTextContainer { 509 | position: relative; 510 | font-size: 14px; 511 | line-height: 18px; 512 | color: #707070; 513 | } 514 | .frameParent13 { 515 | position: absolute; 516 | top: 289px; 517 | left: 26px; 518 | display: flex; 519 | flex-direction: column; 520 | align-items: flex-start; 521 | justify-content: flex-start; 522 | gap: 12px; 523 | } 524 | .frameParent4 { 525 | position: absolute; 526 | right: 0; 527 | bottom: 0; 528 | background-color: #2b2b2b; 529 | width: 360px; 530 | height: 1032px; 531 | overflow: hidden; 532 | } 533 | .desktopWrapper, 534 | .mobileWrapper { 535 | position: absolute; 536 | top: 138px; 537 | left: 537px; 538 | border-radius: 4px; 539 | background-color: #2b2b2b; 540 | width: 594px; 541 | display: flex; 542 | flex-direction: row; 543 | align-items: center; 544 | justify-content: flex-start; 545 | padding: 10px 16px; 546 | box-sizing: border-box; 547 | font-size: 12px; 548 | } 549 | .mobileWrapper { 550 | left: 1169px; 551 | width: 214px; 552 | } 553 | .plusIcon4 { 554 | position: relative; 555 | width: 16px; 556 | height: 16px; 557 | object-fit: cover; 558 | } 559 | .text11 { 560 | position: relative; 561 | letter-spacing: 0.43px; 562 | line-height: 16px; 563 | font-weight: 500; 564 | } 565 | .button3 { 566 | flex-shrink: 0; 567 | flex-direction: row; 568 | padding: 6px 14px; 569 | gap: 6px; 570 | } 571 | .button2, 572 | .button3, 573 | .buttonWrapper { 574 | display: flex; 575 | align-items: center; 576 | justify-content: center; 577 | } 578 | .button2 { 579 | border-radius: 4px; 580 | background-color: #1a73e8; 581 | flex-direction: row; 582 | } 583 | .buttonWrapper { 584 | position: absolute; 585 | top: 354px; 586 | left: calc(50% - 297px); 587 | background-color: #05080d; 588 | border: 1px solid #5d96ff; 589 | box-sizing: border-box; 590 | width: 594px; 591 | flex-direction: column; 592 | padding: 40px 10px; 593 | font-size: 13px; 594 | } 595 | .ionlogoXboxIcon2, 596 | .lighticon { 597 | position: relative; 598 | object-fit: cover; 599 | } 600 | .ionlogoXboxIcon2 { 601 | width: 19.8px; 602 | height: 19.8px; 603 | overflow: hidden; 604 | flex-shrink: 0; 605 | } 606 | .lighticon { 607 | width: 6.6px; 608 | height: 6.6px; 609 | } 610 | .menu, 611 | .pricing { 612 | display: flex; 613 | flex-direction: row; 614 | } 615 | .pricing { 616 | flex-shrink: 0; 617 | align-items: center; 618 | justify-content: center; 619 | gap: 3.3px; 620 | } 621 | .menu { 622 | flex: 1; 623 | align-items: flex-start; 624 | justify-content: flex-start; 625 | gap: 16.5px; 626 | } 627 | .lightbutton, 628 | .lightsearchBox { 629 | border-radius: 12.38px; 630 | height: 19.8px; 631 | overflow: hidden; 632 | display: flex; 633 | align-items: center; 634 | box-sizing: border-box; 635 | } 636 | .lightsearchBox { 637 | background-color: #f0f1f2; 638 | width: 99px; 639 | flex-shrink: 0; 640 | flex-direction: row; 641 | justify-content: flex-start; 642 | padding: 0 0 0 9.074999809265137px; 643 | gap: 4.13px; 644 | } 645 | .lightbutton { 646 | background-color: #4475f2; 647 | flex-direction: column; 648 | justify-content: center; 649 | padding: 0 15.675000190734863px; 650 | color: #fff; 651 | } 652 | .right { 653 | display: flex; 654 | flex-direction: row; 655 | align-items: flex-start; 656 | justify-content: flex-start; 657 | gap: 3.3px; 658 | text-align: center; 659 | font-size: 12px; 660 | font-family: "Plus Jakarta Display"; 661 | } 662 | .container2, 663 | .headerLight041 { 664 | position: absolute; 665 | top: 0; 666 | height: 29.7px; 667 | } 668 | .container2 { 669 | left: 61.88px; 670 | width: 470.25px; 671 | display: flex; 672 | flex-direction: row; 673 | align-items: center; 674 | justify-content: flex-start; 675 | gap: 16.5px; 676 | } 677 | .headerLight041 { 678 | left: calc(50% - 297px); 679 | background-color: #000; 680 | border-bottom: 1px solid #575757; 681 | box-sizing: border-box; 682 | width: 594px; 683 | overflow: hidden; 684 | color: #9a9ea6; 685 | font-family: "IBM Plex Sans"; 686 | } 687 | .bottomBar { 688 | position: absolute; 689 | top: 135.71px; 690 | left: 61.88px; 691 | width: 470.25px; 692 | display: flex; 693 | flex-direction: row; 694 | align-items: center; 695 | justify-content: space-between; 696 | } 697 | .faq { 698 | position: relative; 699 | text-transform: capitalize; 700 | } 701 | .items, 702 | .menu1, 703 | .menu2 { 704 | display: flex; 705 | flex-direction: column; 706 | align-items: flex-start; 707 | } 708 | .items { 709 | flex-shrink: 0; 710 | justify-content: flex-start; 711 | gap: 8.25px; 712 | font-size: 5.78px; 713 | color: #9a9ea6; 714 | } 715 | .menu1, 716 | .menu2 { 717 | top: 0; 718 | justify-content: center; 719 | gap: 9.9px; 720 | } 721 | .menu1 { 722 | position: absolute; 723 | left: 160.88px; 724 | } 725 | .menu2 { 726 | left: 80.44px; 727 | } 728 | .menu2, 729 | .menu3, 730 | .menus { 731 | position: absolute; 732 | } 733 | .menu3 { 734 | top: 0; 735 | left: 0; 736 | display: flex; 737 | flex-direction: column; 738 | align-items: flex-start; 739 | justify-content: center; 740 | gap: 9.9px; 741 | } 742 | .menus { 743 | top: 23.1px; 744 | left: 303.19px; 745 | width: 208.88px; 746 | height: 92.9px; 747 | font-size: 7.43px; 748 | color: #464646; 749 | } 750 | .logoIcon1 { 751 | position: relative; 752 | width: 35.71px; 753 | height: 16.5px; 754 | object-fit: cover; 755 | } 756 | .weAraA2 { 757 | line-height: 9.9px; 758 | } 759 | .readMore { 760 | color: #4475f2; 761 | } 762 | .weAraAContainer { 763 | align-self: stretch; 764 | position: relative; 765 | } 766 | .introduction { 767 | align-self: stretch; 768 | display: flex; 769 | flex-direction: column; 770 | align-items: flex-start; 771 | justify-content: center; 772 | gap: 4.95px; 773 | } 774 | .lightsocialIcons { 775 | position: relative; 776 | width: 8.25px; 777 | height: 8.25px; 778 | object-fit: cover; 779 | } 780 | .lightminiButton { 781 | border-radius: 12.38px; 782 | background-color: #e3ebfd; 783 | width: 19.8px; 784 | height: 19.8px; 785 | overflow: hidden; 786 | flex-shrink: 0; 787 | display: flex; 788 | flex-direction: row; 789 | align-items: center; 790 | justify-content: center; 791 | } 792 | .left, 793 | .socials { 794 | display: flex; 795 | justify-content: flex-start; 796 | } 797 | .socials { 798 | flex-shrink: 0; 799 | flex-direction: row; 800 | align-items: center; 801 | gap: 3.3px; 802 | } 803 | .left { 804 | position: absolute; 805 | top: 23.1px; 806 | left: 61.88px; 807 | flex-direction: column; 808 | align-items: flex-start; 809 | gap: 12.38px; 810 | } 811 | .footerLight041 { 812 | position: absolute; 813 | bottom: 0; 814 | left: calc(50% - 297px); 815 | background-color: #0c0c0c; 816 | width: 594px; 817 | height: 196px; 818 | overflow: hidden; 819 | color: #9a9ea6; 820 | font-family: "IBM Plex Sans"; 821 | } 822 | .text12 { 823 | position: relative; 824 | letter-spacing: 0.25px; 825 | font-weight: 500; 826 | } 827 | .button4 { 828 | background-color: #1a73e8; 829 | border-right: 0.6px solid rgba(0, 0, 0, 0.1); 830 | flex-shrink: 0; 831 | display: flex; 832 | flex-direction: row; 833 | align-items: center; 834 | justify-content: center; 835 | padding: 5.833333969116211px 11.666667938232422px; 836 | } 837 | .chevronDownIcon10 { 838 | position: relative; 839 | width: 10px; 840 | height: 10px; 841 | object-fit: cover; 842 | } 843 | .button6 { 844 | background-color: #1a73e8; 845 | flex-shrink: 0; 846 | display: flex; 847 | flex-direction: row; 848 | align-items: center; 849 | justify-content: center; 850 | padding: 5.833333969116211px 11.666667938232422px; 851 | } 852 | .horizontalButtonGroup1 { 853 | position: absolute; 854 | top: 330px; 855 | left: 18px; 856 | border-radius: 3.5px; 857 | overflow: hidden; 858 | display: flex; 859 | flex-direction: row; 860 | align-items: flex-start; 861 | justify-content: flex-start; 862 | } 863 | .unsplashHcpwe1PrcIcon { 864 | position: absolute; 865 | top: calc(50% - 242px); 866 | right: -36px; 867 | width: 729px; 868 | height: 485px; 869 | object-fit: cover; 870 | } 871 | .giftGuide, 872 | .heresToJoy2 { 873 | position: absolute; 874 | top: 18.95px; 875 | left: calc(50% - 114.5px); 876 | } 877 | .giftGuide { 878 | top: 0; 879 | left: calc(50% - 38.5px); 880 | font-size: 13.41px; 881 | text-transform: uppercase; 882 | font-weight: 600; 883 | color: #69764a; 884 | } 885 | .thereAreMany2 { 886 | position: absolute; 887 | top: 69.67px; 888 | left: 0; 889 | font-size: 8.57px; 890 | color: #7a8365; 891 | text-align: center; 892 | display: inline-block; 893 | width: 299px; 894 | } 895 | .plusIcon5 { 896 | position: relative; 897 | width: 16px; 898 | height: 16px; 899 | object-fit: cover; 900 | display: none; 901 | } 902 | .text14 { 903 | position: relative; 904 | letter-spacing: 0.43px; 905 | line-height: 16px; 906 | text-transform: uppercase; 907 | font-weight: 500; 908 | } 909 | .button7 { 910 | position: absolute; 911 | top: 105.95px; 912 | left: calc(50% - 55.5px); 913 | border-radius: 4px; 914 | background-color: #536136; 915 | display: flex; 916 | flex-direction: row; 917 | align-items: center; 918 | justify-content: center; 919 | font-size: 13px; 920 | color: #fff; 921 | font-family: "Public Sans"; 922 | } 923 | .heresToJoyParent { 924 | position: absolute; 925 | top: 95px; 926 | left: calc(50% - 149px); 927 | width: 299px; 928 | height: 133.95px; 929 | } 930 | .unsplashHcpwe1PrcParent { 931 | position: absolute; 932 | top: 0; 933 | left: 0; 934 | background-color: #fff; 935 | width: 594px; 936 | height: 324px; 937 | overflow: hidden; 938 | text-align: left; 939 | font-size: 36.22px; 940 | color: #536136; 941 | font-family: Inter; 942 | } 943 | .groupChild { 944 | position: absolute; 945 | top: 312px; 946 | left: 552px; 947 | width: 24px; 948 | height: 24px; 949 | object-fit: cover; 950 | } 951 | .horizontalButtonGroupParent { 952 | position: absolute; 953 | top: 30px; 954 | left: 0; 955 | width: 594px; 956 | height: 351.67px; 957 | text-align: center; 958 | font-size: 8.75px; 959 | } 960 | .frameParent14 { 961 | position: absolute; 962 | top: 193px; 963 | left: 537px; 964 | background-color: #000; 965 | width: 594px; 966 | height: 805px; 967 | overflow: hidden; 968 | font-size: 5.78px; 969 | } 970 | .ionlogoXboxIcon3 { 971 | position: absolute; 972 | top: calc(50% - 8px); 973 | left: 16px; 974 | width: 16px; 975 | height: 16px; 976 | overflow: hidden; 977 | object-fit: cover; 978 | } 979 | .darkicon { 980 | position: relative; 981 | width: 18px; 982 | height: 18px; 983 | object-fit: cover; 984 | } 985 | .darkminiButton { 986 | position: absolute; 987 | top: calc(50% - 9px); 988 | right: 16px; 989 | width: 18px; 990 | height: 18px; 991 | overflow: hidden; 992 | display: flex; 993 | flex-direction: row; 994 | align-items: center; 995 | justify-content: center; 996 | } 997 | .ionlogoXboxParent { 998 | position: absolute; 999 | top: 0; 1000 | left: 0; 1001 | background-color: #000; 1002 | border-bottom: 1px solid #575757; 1003 | box-sizing: border-box; 1004 | width: 214px; 1005 | height: 30px; 1006 | overflow: hidden; 1007 | } 1008 | .logoChild, 1009 | .swipeIcon1 { 1010 | position: absolute; 1011 | height: 34.93%; 1012 | width: 45.31%; 1013 | top: 35.53%; 1014 | right: 0; 1015 | bottom: 29.53%; 1016 | left: 54.69%; 1017 | max-width: 100%; 1018 | overflow: hidden; 1019 | max-height: 100%; 1020 | object-fit: cover; 1021 | } 1022 | .logoChild { 1023 | height: 100%; 1024 | width: 46.2%; 1025 | top: 0; 1026 | right: 53.8%; 1027 | bottom: 0; 1028 | left: 0; 1029 | } 1030 | .logo { 1031 | position: absolute; 1032 | height: 12.42%; 1033 | width: 29.91%; 1034 | top: 6.92%; 1035 | right: 62.62%; 1036 | bottom: 80.66%; 1037 | left: 7.48%; 1038 | } 1039 | .weAraAContainer1 { 1040 | position: absolute; 1041 | top: 56.03px; 1042 | left: 16px; 1043 | display: inline-block; 1044 | width: 182px; 1045 | } 1046 | .socials1 { 1047 | position: absolute; 1048 | top: 178px; 1049 | left: 51px; 1050 | display: flex; 1051 | flex-direction: row; 1052 | align-items: center; 1053 | justify-content: flex-start; 1054 | gap: 3.3px; 1055 | } 1056 | .allRightsReserved3 { 1057 | position: absolute; 1058 | top: 214px; 1059 | left: calc(50% - 44px); 1060 | } 1061 | .aboutParent, 1062 | .frameParent16 { 1063 | display: flex; 1064 | align-items: flex-start; 1065 | } 1066 | .aboutParent { 1067 | width: 182px; 1068 | flex-shrink: 0; 1069 | flex-direction: row; 1070 | justify-content: space-between; 1071 | } 1072 | .frameParent16 { 1073 | position: absolute; 1074 | top: 110px; 1075 | left: 16px; 1076 | flex-direction: column; 1077 | justify-content: flex-start; 1078 | gap: 10px; 1079 | font-size: 7.43px; 1080 | color: #464646; 1081 | } 1082 | .logoParent { 1083 | position: absolute; 1084 | bottom: 0; 1085 | left: calc(50% - 107px); 1086 | background-color: #0c0c0c; 1087 | width: 214px; 1088 | height: 238px; 1089 | overflow: hidden; 1090 | } 1091 | .unsplashHcpwe1PrcIcon1 { 1092 | position: absolute; 1093 | top: calc(50% - 110.5px); 1094 | left: calc(50% - 182px); 1095 | width: 333px; 1096 | height: 221px; 1097 | object-fit: cover; 1098 | } 1099 | .giftGuide1, 1100 | .heresToJoy3 { 1101 | position: absolute; 1102 | top: 9.82px; 1103 | left: calc(50% - 59.36px); 1104 | } 1105 | .giftGuide1 { 1106 | top: 0; 1107 | left: calc(50% - 19.96px); 1108 | font-size: 6.95px; 1109 | text-transform: uppercase; 1110 | font-weight: 600; 1111 | color: #69764a; 1112 | } 1113 | .thereAreMany3 { 1114 | position: absolute; 1115 | top: 36.12px; 1116 | left: 0; 1117 | font-size: 4.44px; 1118 | color: #7a8365; 1119 | text-align: center; 1120 | display: inline-block; 1121 | width: 155px; 1122 | } 1123 | .plusIcon6 { 1124 | position: relative; 1125 | width: 8.29px; 1126 | height: 8.29px; 1127 | object-fit: cover; 1128 | display: none; 1129 | } 1130 | .text15 { 1131 | position: relative; 1132 | letter-spacing: 0.22px; 1133 | line-height: 8.29px; 1134 | text-transform: uppercase; 1135 | font-weight: 500; 1136 | } 1137 | .button10, 1138 | .button9 { 1139 | display: flex; 1140 | flex-direction: row; 1141 | align-items: center; 1142 | justify-content: center; 1143 | } 1144 | .button10 { 1145 | padding: 3.110367774963379px 7.2575249671936035px; 1146 | gap: 3.11px; 1147 | } 1148 | .button9 { 1149 | position: absolute; 1150 | top: 54.92px; 1151 | left: calc(50% - 28.61px); 1152 | border-radius: 2.07px; 1153 | background-color: #536136; 1154 | width: 48.73px; 1155 | height: 14.52px; 1156 | font-size: 6.74px; 1157 | color: #fff; 1158 | font-family: "Public Sans"; 1159 | } 1160 | .heresToJoyGroup { 1161 | position: absolute; 1162 | top: 52px; 1163 | left: calc(50% - 78px); 1164 | width: 155px; 1165 | height: 69.44px; 1166 | } 1167 | .unsplashHcpwe1PrcGroup { 1168 | position: absolute; 1169 | top: 0; 1170 | left: 0; 1171 | background-color: #fff; 1172 | width: 214px; 1173 | height: 173px; 1174 | overflow: hidden; 1175 | } 1176 | .button11, 1177 | .buttonFrame { 1178 | display: flex; 1179 | align-items: center; 1180 | justify-content: center; 1181 | } 1182 | .button11 { 1183 | border-radius: 4px; 1184 | background-color: #5d96ff; 1185 | flex-direction: row; 1186 | } 1187 | .buttonFrame { 1188 | position: absolute; 1189 | top: 173px; 1190 | left: calc(50% - 107px); 1191 | background-color: #05080d; 1192 | border: 1px solid #5d96ff; 1193 | box-sizing: border-box; 1194 | width: 214px; 1195 | flex-direction: column; 1196 | padding: 40px 10px; 1197 | font-size: 13px; 1198 | color: #fff; 1199 | font-family: "Public Sans"; 1200 | } 1201 | .frameParent15, 1202 | .groupDiv { 1203 | position: absolute; 1204 | top: 30px; 1205 | left: 0; 1206 | width: 214px; 1207 | height: 281px; 1208 | font-size: 18.78px; 1209 | color: #536136; 1210 | font-family: Inter; 1211 | } 1212 | .frameParent15 { 1213 | top: 193px; 1214 | left: 1169px; 1215 | background-color: #000; 1216 | height: 724px; 1217 | overflow: hidden; 1218 | font-size: 5.78px; 1219 | color: #9a9ea6; 1220 | font-family: "IBM Plex Sans"; 1221 | } 1222 | .editor { 1223 | position: relative; 1224 | background-color: #1e1e1e; 1225 | width: 100%; 1226 | height: 1080px; 1227 | overflow: hidden; 1228 | text-align: left; 1229 | font-size: 16px; 1230 | color: #fff; 1231 | font-family: "Public Sans"; 1232 | } 1233 | -------------------------------------------------------------------------------- /tailwind.config.ts: -------------------------------------------------------------------------------- 1 | import type { Config } from 'tailwindcss' 2 | 3 | const config: Config = { 4 | content: [ 5 | './src/pages/**/*.{js,ts,jsx,tsx,mdx}', 6 | './src/components/**/*.{js,ts,jsx,tsx,mdx}', 7 | './src/app/**/*.{js,ts,jsx,tsx,mdx}', 8 | ], 9 | theme: { 10 | extend: { 11 | backgroundImage: { 12 | 'gradient-radial': 'radial-gradient(var(--tw-gradient-stops))', 13 | 'gradient-conic': 14 | 'conic-gradient(from 180deg at 50% 50%, var(--tw-gradient-stops))', 15 | }, 16 | colors: { 17 | black: "#000", 18 | tomato: { 19 | "100": "#f1614a", 20 | "200": "rgba(241, 97, 74, 0.3)", 21 | }, 22 | white: "#fff", 23 | goldenrod: "#ffbb37", 24 | }, 25 | spacing: {}, 26 | fontFamily: { 27 | inter: "Inter", 28 | inconsolata: "Inconsolata", 29 | ligconsolata: "Ligconsolata", 30 | }, 31 | borderRadius: { 32 | "2xs": "11px", 33 | }, 34 | }, 35 | fontSize: { 36 | "18xl": "37px", 37 | "11xl": "30px", 38 | inherit: "inherit", 39 | }, 40 | }, 41 | plugins: [], 42 | } 43 | export default config 44 | -------------------------------------------------------------------------------- /tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "target": "es5", 4 | "lib": ["dom", "dom.iterable", "esnext"], 5 | "allowJs": true, 6 | "skipLibCheck": true, 7 | "strict": true, 8 | "noEmit": true, 9 | "esModuleInterop": true, 10 | "module": "esnext", 11 | "moduleResolution": "bundler", 12 | "resolveJsonModule": true, 13 | "isolatedModules": true, 14 | "jsx": "preserve", 15 | "incremental": true, 16 | "plugins": [ 17 | { 18 | "name": "next" 19 | } 20 | ], 21 | "paths": { 22 | "@/*": ["./src/*"] 23 | } 24 | }, 25 | "include": ["next-env.d.ts", "**/*.ts", "**/*.tsx", ".next/types/**/*.ts"], 26 | "exclude": ["node_modules"] 27 | } 28 | --------------------------------------------------------------------------------