├── .babelrc ├── .env ├── .eslintrc.json ├── .gitignore ├── Imagens ├── WebAccessibility.png ├── autor1.jpg ├── autor2.jpg ├── codigo.jpg ├── logo.svg └── react.jpg ├── README.md ├── jsconfig.json ├── next.config.js ├── package-lock.json ├── package.json ├── pages ├── 404.jsx ├── _app.jsx ├── _document.jsx ├── index.jsx └── post │ └── [slug].jsx ├── public ├── favicon.ico ├── logo.svg └── vercel.svg ├── schemas ├── author.js ├── blockContent.js ├── index.js └── post.js ├── src ├── Components │ ├── Bar │ │ ├── Bar.jsx │ │ └── Bar.module.scss │ ├── Cardpost │ │ ├── Cardpost.jsx │ │ └── Cardpost.module.scss │ ├── Footer │ │ ├── Footer.jsx │ │ └── Footer.module.scss │ └── Heading │ │ ├── Heading.jsx │ │ └── Heading.module.scss ├── Layout │ └── MainLayout.jsx ├── UI │ ├── Author │ │ ├── Author.jsx │ │ └── Author.module.scss │ ├── Error │ │ ├── Error.jsx │ │ └── Error.module.scss │ └── Logo │ │ └── Logo.jsx └── sanity.js └── styles ├── Custom404.module.scss ├── Home.module.scss ├── Post.module.scss ├── globals.scss ├── mixins.scss └── variables.scss /.babelrc: -------------------------------------------------------------------------------- 1 | { 2 | "presets": ["next/babel"], 3 | "plugins": [] 4 | } -------------------------------------------------------------------------------- /.env: -------------------------------------------------------------------------------- 1 | NEXT_PUBLIC_PROJECT_ID='3tmy3ohm' 2 | NEXT_PUBLIC_DATASET='production' 3 | NEXT_PUBLIC_API_VERSION='2022-12-14' 4 | NEXT_PUBLIC_USE_CDN=false -------------------------------------------------------------------------------- /.eslintrc.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": ["next/babel","next/core-web-vitals"] 3 | } -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # See https://help.github.com/articles/ignoring-files/ for more about ignoring files. 2 | 3 | # dependencies 4 | /node_modules 5 | /.pnp 6 | .pnp.js 7 | 8 | # testing 9 | /coverage 10 | 11 | # next.js 12 | /.next/ 13 | /out/ 14 | 15 | # production 16 | /build 17 | 18 | # misc 19 | .DS_Store 20 | *.pem 21 | 22 | # debug 23 | npm-debug.log* 24 | yarn-debug.log* 25 | yarn-error.log* 26 | .pnpm-debug.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 | -------------------------------------------------------------------------------- /Imagens/WebAccessibility.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/canaldofront/minimal-blog/bbed3b3044975ea1b5e4b34b23e40f9756d2cbc4/Imagens/WebAccessibility.png -------------------------------------------------------------------------------- /Imagens/autor1.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/canaldofront/minimal-blog/bbed3b3044975ea1b5e4b34b23e40f9756d2cbc4/Imagens/autor1.jpg -------------------------------------------------------------------------------- /Imagens/autor2.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/canaldofront/minimal-blog/bbed3b3044975ea1b5e4b34b23e40f9756d2cbc4/Imagens/autor2.jpg -------------------------------------------------------------------------------- /Imagens/codigo.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/canaldofront/minimal-blog/bbed3b3044975ea1b5e4b34b23e40f9756d2cbc4/Imagens/codigo.jpg -------------------------------------------------------------------------------- /Imagens/logo.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /Imagens/react.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/canaldofront/minimal-blog/bbed3b3044975ea1b5e4b34b23e40f9756d2cbc4/Imagens/react.jpg -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | This is a [Next.js](https://nextjs.org/) project bootstrapped with [`create-next-app`](https://github.com/vercel/next.js/tree/canary/packages/create-next-app). 2 | 3 | ## Getting Started 4 | 5 | First, run the development server: 6 | 7 | ```bash 8 | npm run dev 9 | # or 10 | yarn dev 11 | ``` 12 | 13 | Open [http://localhost:3000](http://localhost:3000) with your browser to see the result. 14 | 15 | You can start editing the page by modifying `pages/index.js`. The page auto-updates as you edit the file. 16 | 17 | [API routes](https://nextjs.org/docs/api-routes/introduction) can be accessed on [http://localhost:3000/api/hello](http://localhost:3000/api/hello). This endpoint can be edited in `pages/api/hello.js`. 18 | 19 | The `pages/api` directory is mapped to `/api/*`. Files in this directory are treated as [API routes](https://nextjs.org/docs/api-routes/introduction) instead of React pages. 20 | 21 | ## Learn More 22 | 23 | To learn more about Next.js, take a look at the following resources: 24 | 25 | - [Next.js Documentation](https://nextjs.org/docs) - learn about Next.js features and API. 26 | - [Learn Next.js](https://nextjs.org/learn) - an interactive Next.js tutorial. 27 | 28 | You can check out [the Next.js GitHub repository](https://github.com/vercel/next.js/) - your feedback and contributions are welcome! 29 | 30 | ## Deploy on Vercel 31 | 32 | The easiest way to deploy your Next.js app is to use the [Vercel Platform](https://vercel.com/new?utm_medium=default-template&filter=next.js&utm_source=create-next-app&utm_campaign=create-next-app-readme) from the creators of Next.js. 33 | 34 | Check out our [Next.js deployment documentation](https://nextjs.org/docs/deployment) for more details. 35 | -------------------------------------------------------------------------------- /jsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "baseUrl": ".", 4 | "paths": { 5 | "src/*": ["src/*"], 6 | "styles/*": ["styles/*"], 7 | } 8 | } 9 | } -------------------------------------------------------------------------------- /next.config.js: -------------------------------------------------------------------------------- 1 | /** @type {import('next').NextConfig} */ 2 | const nextConfig = { 3 | reactStrictMode: true, 4 | images: { 5 | domains: ['cdn.sanity.io'], 6 | }, 7 | }; 8 | 9 | module.exports = nextConfig; 10 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "minimal-blog", 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 | "@portabletext/react": "^2.0.0", 13 | "eslint": "8.29.0", 14 | "eslint-config-next": "13.0.6", 15 | "next": "13.0.6", 16 | "next-sanity": "^3.1.3", 17 | "next-sanity-image": "^5.0.0", 18 | "react": "18.2.0", 19 | "react-dom": "18.2.0", 20 | "react-icons": "^4.7.1" 21 | }, 22 | "devDependencies": { 23 | "sass": "^1.56.1" 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /pages/404.jsx: -------------------------------------------------------------------------------- 1 | import Error from 'src/UI/Error/Error'; 2 | import styles from 'styles/Custom404.module.scss'; 3 | 4 | const Custom404 = () => { 5 | return ( 6 |
7 |

Oops!! Error 404

8 | 9 |
10 | ); 11 | }; 12 | 13 | export default Custom404; 14 | -------------------------------------------------------------------------------- /pages/_app.jsx: -------------------------------------------------------------------------------- 1 | import MainLayout from 'src/Layout/MainLayout'; 2 | import '../styles/globals.scss'; 3 | 4 | function MyApp({ Component, pageProps }) { 5 | return ( 6 | 7 | 8 | 9 | ); 10 | } 11 | 12 | export default MyApp; 13 | -------------------------------------------------------------------------------- /pages/_document.jsx: -------------------------------------------------------------------------------- 1 | import { Html, Head, Main, NextScript } from 'next/document'; 2 | 3 | export default function Document() { 4 | return ( 5 | 6 | 7 | 8 | 9 | 13 | 14 | 15 |
16 | 17 | 18 | 19 | ); 20 | } 21 | -------------------------------------------------------------------------------- /pages/index.jsx: -------------------------------------------------------------------------------- 1 | import Cardpost from 'src/Components/Cardpost/Cardpost'; 2 | import styles from 'styles/Home.module.scss'; 3 | import client from 'src/sanity'; 4 | import { useRouter } from 'next/router'; 5 | import Error from 'src/UI/Error/Error'; 6 | 7 | export default function Home({ posts, author }) { 8 | const router = useRouter(); 9 | 10 | // Filter Posts 11 | const searchFor = router.query.search || null; 12 | const foundPosts = 13 | posts?.filter((post) => post.title.toLowerCase().includes(searchFor)) || []; 14 | 15 | // Pagination 16 | const numberOfPosts = searchFor === null ? posts.length : foundPosts.length; 17 | 18 | const postsPerPage = 6; 19 | const lastPage = Math.ceil(numberOfPosts / postsPerPage); 20 | 21 | let currentPage = +router.query.page || 1; 22 | 23 | if (currentPage < 1) currentPage = 1; 24 | if (currentPage > lastPage) currentPage = lastPage; 25 | 26 | const inicialIndex = postsPerPage * (currentPage - 1); 27 | const finalIndex = postsPerPage * currentPage; 28 | 29 | const disableLeftButton = currentPage <= 1; 30 | const disableRightButton = currentPage >= lastPage; 31 | const disablePagination = numberOfPosts <= postsPerPage; 32 | 33 | // Render Posts 34 | const currentPostList = searchFor === null ? posts : foundPosts; 35 | 36 | const renderPosts = currentPostList 37 | .sort((a, b) => new Date(b.publishedAt) - new Date(a.publishedAt)) 38 | .slice(inicialIndex, finalIndex) 39 | .map((post) => ); 40 | 41 | return ( 42 |
43 |

Últimos artigos do Minimal Blog

44 |
{renderPosts}
45 | {searchFor !== null && foundPosts.length === 0 && ( 46 | 47 | )} 48 | {!disablePagination && ( 49 |
50 | 56 | 57 | {currentPage} / {lastPage} 58 | 59 | 65 |
66 | )} 67 |
68 | ); 69 | } 70 | 71 | export const getStaticProps = async () => { 72 | const posts = await client.fetch(`*[_type == "post"]`); 73 | const author = await client.fetch(`*[_type == "author"]`); 74 | 75 | return { 76 | props: { 77 | posts, 78 | author, 79 | }, 80 | }; 81 | }; 82 | -------------------------------------------------------------------------------- /pages/post/[slug].jsx: -------------------------------------------------------------------------------- 1 | import client from 'src/sanity'; 2 | import Author from 'src/UI/Author/Author'; 3 | import styles from 'styles/Post.module.scss'; 4 | import Image from 'next/image'; 5 | import { useNextSanityImage } from 'next-sanity-image'; 6 | import { PortableText } from '@portabletext/react'; 7 | 8 | const Post = ({ post, author }) => { 9 | const { 10 | title, 11 | subtitle, 12 | mainImage, 13 | body, 14 | author: authorRef, 15 | publishedAt, 16 | } = post || {}; 17 | 18 | const getAuthor = author?.find((author) => author._id === authorRef._ref); 19 | const imageProps = useNextSanityImage(client, mainImage); 20 | 21 | const ptComponents = { 22 | types: { 23 | image: ({ value }) => { 24 | if (!value.asset._ref) return null; 25 | return ( 26 | {title 31 | ); 32 | }, 33 | }, 34 | }; 35 | 36 | return ( 37 |
38 |
39 |

{title}

40 |

{subtitle}

41 | 42 |
43 |
44 |
45 | {title} 46 |
47 | 48 |
49 |
50 | ); 51 | }; 52 | 53 | export default Post; 54 | 55 | export const getStaticPaths = async () => { 56 | const query = `*[_type == "post" && defined(slug.current)[]].slug.current`; 57 | const paths = await client.fetch(query); 58 | 59 | return { 60 | paths: paths.map((slug) => ({ params: { slug } })), 61 | fallback: true, 62 | }; 63 | }; 64 | 65 | export const getStaticProps = async (context) => { 66 | const { slug = '' } = context.params; 67 | 68 | const query = `*[_type == "post" && slug.current == "${slug}"][0]`; 69 | const post = await client.fetch(query); 70 | 71 | const author = await client.fetch(`*[_type == "author"]`); 72 | 73 | return { 74 | props: { 75 | post, 76 | author, 77 | }, 78 | }; 79 | }; 80 | -------------------------------------------------------------------------------- /public/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/canaldofront/minimal-blog/bbed3b3044975ea1b5e4b34b23e40f9756d2cbc4/public/favicon.ico -------------------------------------------------------------------------------- /public/logo.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /public/vercel.svg: -------------------------------------------------------------------------------- 1 | 3 | 4 | -------------------------------------------------------------------------------- /schemas/author.js: -------------------------------------------------------------------------------- 1 | import {defineField, defineType} from 'sanity' 2 | 3 | export default defineType({ 4 | name: 'author', 5 | title: 'Author', 6 | type: 'document', 7 | fields: [ 8 | defineField({ 9 | name: 'name', 10 | title: 'Name', 11 | type: 'string', 12 | }), 13 | defineField({ 14 | name: 'image', 15 | title: 'Image', 16 | type: 'image', 17 | options: { 18 | hotspot: true, 19 | }, 20 | }), 21 | ], 22 | }) 23 | -------------------------------------------------------------------------------- /schemas/blockContent.js: -------------------------------------------------------------------------------- 1 | import {defineType, defineArrayMember} from 'sanity' 2 | 3 | /** 4 | * This is the schema definition for the rich text fields used for 5 | * for this blog studio. When you import it in schemas.js it can be 6 | * reused in other parts of the studio with: 7 | * { 8 | * name: 'someName', 9 | * title: 'Some title', 10 | * type: 'blockContent' 11 | * } 12 | */ 13 | export default defineType({ 14 | title: 'Block Content', 15 | name: 'blockContent', 16 | type: 'array', 17 | of: [ 18 | defineArrayMember({ 19 | title: 'Block', 20 | type: 'block', 21 | // Styles let you set what your user can mark up blocks with. These 22 | // correspond with HTML tags, but you can set any title or value 23 | // you want and decide how you want to deal with it where you want to 24 | // use your content. 25 | styles: [ 26 | {title: 'Normal', value: 'normal'}, 27 | {title: 'H1', value: 'h1'}, 28 | {title: 'H2', value: 'h2'}, 29 | {title: 'H3', value: 'h3'}, 30 | {title: 'H4', value: 'h4'}, 31 | {title: 'Quote', value: 'blockquote'}, 32 | ], 33 | lists: [{title: 'Bullet', value: 'bullet'}], 34 | // Marks let you mark up inline text in the block editor. 35 | marks: { 36 | // Decorators usually describe a single property – e.g. a typographic 37 | // preference or highlighting by editors. 38 | decorators: [ 39 | {title: 'Strong', value: 'strong'}, 40 | {title: 'Emphasis', value: 'em'}, 41 | ], 42 | // Annotations can be any object structure – e.g. a link or a footnote. 43 | annotations: [ 44 | { 45 | title: 'URL', 46 | name: 'link', 47 | type: 'object', 48 | fields: [ 49 | { 50 | title: 'URL', 51 | name: 'href', 52 | type: 'url', 53 | }, 54 | ], 55 | }, 56 | ], 57 | }, 58 | }), 59 | // You can add additional types here. Note that you can't use 60 | // primitive types such as 'string' and 'number' in the same array 61 | // as a block type. 62 | defineArrayMember({ 63 | type: 'image', 64 | options: {hotspot: true}, 65 | }), 66 | ], 67 | }) 68 | -------------------------------------------------------------------------------- /schemas/index.js: -------------------------------------------------------------------------------- 1 | import blockContent from './blockContent' 2 | import post from './post' 3 | import author from './author' 4 | 5 | export const schemaTypes = [post, author, blockContent] 6 | -------------------------------------------------------------------------------- /schemas/post.js: -------------------------------------------------------------------------------- 1 | import {defineField, defineType} from 'sanity' 2 | 3 | export default defineType({ 4 | name: 'post', 5 | title: 'Post', 6 | type: 'document', 7 | fields: [ 8 | defineField({ 9 | name: 'title', 10 | title: 'Title', 11 | type: 'string', 12 | }), 13 | defineField({ 14 | name: 'subtitle', 15 | title: 'Subtitle', 16 | type: 'string', 17 | }), 18 | defineField({ 19 | name: 'short_text', 20 | title: 'Short Text', 21 | type: 'text', 22 | }), 23 | defineField({ 24 | name: 'slug', 25 | title: 'Slug', 26 | type: 'slug', 27 | options: { 28 | source: 'title', 29 | maxLength: 96, 30 | }, 31 | }), 32 | defineField({ 33 | name: 'author', 34 | title: 'Author', 35 | type: 'reference', 36 | to: {type: 'author'}, 37 | }), 38 | defineField({ 39 | name: 'mainImage', 40 | title: 'Main image', 41 | type: 'image', 42 | options: { 43 | hotspot: true, 44 | }, 45 | }), 46 | defineField({ 47 | name: 'publishedAt', 48 | title: 'Published at', 49 | type: 'datetime', 50 | }), 51 | defineField({ 52 | name: 'body', 53 | title: 'Body', 54 | type: 'blockContent', 55 | }), 56 | ], 57 | 58 | preview: { 59 | select: { 60 | title: 'title', 61 | author: 'author.name', 62 | media: 'mainImage', 63 | }, 64 | prepare(selection) { 65 | const {author} = selection 66 | return {...selection, subtitle: author && `by ${author}`} 67 | }, 68 | }, 69 | }) 70 | -------------------------------------------------------------------------------- /src/Components/Bar/Bar.jsx: -------------------------------------------------------------------------------- 1 | import styles from './Bar.module.scss'; 2 | 3 | const Bar = () => { 4 | return ( 5 |
6 | Novos artigos todas as terças! 7 |
8 | ); 9 | }; 10 | 11 | export default Bar; 12 | -------------------------------------------------------------------------------- /src/Components/Bar/Bar.module.scss: -------------------------------------------------------------------------------- 1 | @import 'styles/variables.scss'; 2 | 3 | .bar { 4 | background-color: $primary; 5 | padding: 1.5rem 0; 6 | text-align: center; 7 | margin-bottom: 3rem; 8 | 9 | span { 10 | font-size: 1.4rem; 11 | color: $white; 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /src/Components/Cardpost/Cardpost.jsx: -------------------------------------------------------------------------------- 1 | import Author from 'src/UI/Author/Author'; 2 | import styles from './Cardpost.module.scss'; 3 | import Link from 'next/link'; 4 | import client from 'src/sanity'; 5 | import { useNextSanityImage } from 'next-sanity-image'; 6 | import Image from 'next/image'; 7 | 8 | const Cardpost = ({ post, author }) => { 9 | const { 10 | author: authorRef, 11 | title, 12 | mainImage, 13 | publishedAt, 14 | short_text, 15 | slug, 16 | } = post || {}; 17 | 18 | const imageProps = useNextSanityImage(client, mainImage); 19 | const getAuthor = author?.find((author) => author._id === authorRef._ref); 20 | 21 | return ( 22 |
23 |
24 | {title} 25 |
26 |
27 |

{title}

28 |

{short_text}

29 |
30 | 31 | 32 | Continuar lendo → 33 | 34 |
35 |
36 |
37 | ); 38 | }; 39 | 40 | export default Cardpost; 41 | -------------------------------------------------------------------------------- /src/Components/Cardpost/Cardpost.module.scss: -------------------------------------------------------------------------------- 1 | @import 'styles/variables.scss'; 2 | @import 'styles/mixins.scss'; 3 | 4 | .post { 5 | display: flex; 6 | align-items: center; 7 | gap: 2rem; 8 | 9 | @include device(tablet) { 10 | flex-direction: column; 11 | max-width: 50rem; 12 | } 13 | 14 | &:not(:last-of-type) { 15 | margin-bottom: 4rem; 16 | 17 | @include device(tablet) { 18 | margin-bottom: 6rem; 19 | } 20 | } 21 | 22 | &:hover { 23 | cursor: pointer; 24 | } 25 | 26 | .image { 27 | img { 28 | max-width: 20rem; 29 | height: 20rem; 30 | 31 | @include device(tablet) { 32 | max-width: 100%; 33 | height: auto; 34 | } 35 | } 36 | } 37 | 38 | .content { 39 | h2 { 40 | font-family: $titleFontFamily; 41 | font-weight: 400; 42 | margin-bottom: 1rem; 43 | } 44 | 45 | p { 46 | margin-bottom: 2rem; 47 | } 48 | } 49 | 50 | .footer { 51 | display: flex; 52 | justify-content: space-between; 53 | align-items: center; 54 | 55 | a { 56 | text-decoration: none; 57 | color: $black; 58 | 59 | &:hover { 60 | font-weight: 600; 61 | } 62 | } 63 | } 64 | } 65 | -------------------------------------------------------------------------------- /src/Components/Footer/Footer.jsx: -------------------------------------------------------------------------------- 1 | import Logo from 'src/UI/Logo/Logo'; 2 | import styles from './Footer.module.scss'; 3 | import { AiFillInstagram } from 'react-icons/ai'; 4 | import { IoLogoWhatsapp } from 'react-icons/io'; 5 | import { MdEmail } from 'react-icons/md'; 6 | import { BsTelegram } from 'react-icons/bs'; 7 | 8 | const social = [ 9 | { component: , url: '#' }, 10 | { component: , url: '#' }, 11 | { component: , url: '#' }, 12 | { component: , url: '#' }, 13 | ]; 14 | 15 | const Footer = () => { 16 | const renderSocial = social.map((el, i) => ( 17 | 18 | {el.component} 19 | 20 | )); 21 | 22 | return ( 23 |
24 |
25 |
26 | 27 |

Compartilhando conhecimento sobre o mundo de tecnologia.

28 |
{renderSocial}
29 |
30 | 31 | © Minimal Blog - Todos os direitos reservados. 32 | 33 |
34 |
35 | ); 36 | }; 37 | 38 | export default Footer; 39 | -------------------------------------------------------------------------------- /src/Components/Footer/Footer.module.scss: -------------------------------------------------------------------------------- 1 | @import 'styles/variables.scss'; 2 | @import 'styles/mixins.scss'; 3 | 4 | .footer-wrapper { 5 | padding-top: 8rem; 6 | padding-bottom: 2rem; 7 | background-color: $secondary; 8 | 9 | .footer { 10 | @include max-width(large); 11 | display: flex; 12 | flex-direction: column; 13 | 14 | .content { 15 | margin-bottom: 6rem; 16 | max-width: 25rem; 17 | 18 | p { 19 | margin: 1rem 0; 20 | } 21 | 22 | .social { 23 | display: flex; 24 | gap: 1rem; 25 | 26 | a { 27 | text-decoration: none; 28 | } 29 | 30 | svg { 31 | width: 2rem; 32 | height: 2rem; 33 | color: $primary; 34 | } 35 | } 36 | } 37 | 38 | .copy { 39 | align-self: center; 40 | font-size: 1.4rem; 41 | } 42 | } 43 | } 44 | -------------------------------------------------------------------------------- /src/Components/Heading/Heading.jsx: -------------------------------------------------------------------------------- 1 | import styles from './Heading.module.scss'; 2 | import { BiSearchAlt } from 'react-icons/bi'; 3 | import Logo from 'src/UI/Logo/Logo'; 4 | 5 | const Heading = () => { 6 | return ( 7 |
8 | 9 |
10 |
11 | 12 | 18 | 21 |
22 |
23 |
24 | ); 25 | }; 26 | 27 | export default Heading; 28 | -------------------------------------------------------------------------------- /src/Components/Heading/Heading.module.scss: -------------------------------------------------------------------------------- 1 | @import 'styles/variables.scss'; 2 | @import 'styles/mixins.scss'; 3 | 4 | .heading { 5 | @include max-width(large); 6 | display: flex; 7 | justify-content: space-between; 8 | align-items: center; 9 | margin-bottom: $marginBottom; 10 | 11 | @include device(tablet) { 12 | flex-direction: column; 13 | gap: 2rem; 14 | } 15 | 16 | .search { 17 | width: 100%; 18 | max-width: 50rem; 19 | background-color: $secondary; 20 | border: 1rem; 21 | position: relative; 22 | 23 | label { 24 | display: none; 25 | opacity: 0; 26 | width: 0; 27 | height: 0; 28 | position: absolute; 29 | top: 0; 30 | left: 0; 31 | } 32 | 33 | input { 34 | border: none; 35 | outline: none; 36 | background-color: transparent; 37 | width: 100%; 38 | padding: 1.5rem 5.5rem 1.5rem 2rem; 39 | 40 | &::placeholder { 41 | font-family: $fontFamily; 42 | color: $gray; 43 | } 44 | } 45 | 46 | .button { 47 | border: none; 48 | outline: none; 49 | background-color: transparent; 50 | padding: 0.5rem; 51 | position: absolute; 52 | top: 50%; 53 | right: 2rem; 54 | transform: translateY(-40%); 55 | 56 | svg { 57 | width: 2rem; 58 | height: 2rem; 59 | color: $gray; 60 | } 61 | 62 | &:hover { 63 | cursor: pointer; 64 | } 65 | } 66 | } 67 | } 68 | -------------------------------------------------------------------------------- /src/Layout/MainLayout.jsx: -------------------------------------------------------------------------------- 1 | import Footer from 'src/Components/Footer/Footer'; 2 | import Heading from 'src/Components/Heading/Heading'; 3 | import Bar from '../Components/Bar/Bar'; 4 | 5 | const MainLayout = ({ children }) => { 6 | return ( 7 | <> 8 |
9 | 10 | 11 |
12 |
{children}
13 |