├── .all-contributorsrc ├── .eslintrc.json ├── .github └── holopin.yml ├── .gitignore ├── .nvmrc ├── .prettierrc ├── .tool-versions ├── .vscode ├── extensions.json └── settings.json ├── CODE_OF_CONDUCT.md ├── CONTRIBUTING.md ├── LICENSE.md ├── README.md ├── next-i18next.config.js ├── next.config.js ├── package-lock.json ├── package.json ├── postcss.config.js ├── public ├── favicon.ico ├── icons │ ├── arrow.svg │ ├── devsnorte-hero-light.svg │ ├── devsnorte-hero.svg │ ├── dot.svg │ ├── favicon.svg │ ├── line-section.svg │ ├── loading.svg │ ├── logo-light.svg │ ├── logo.svg │ ├── menu.svg │ ├── rectangle-section.svg │ ├── star.svg │ └── translate.svg ├── images │ ├── eventos.png │ ├── logos │ │ ├── amazoniaonline.png │ │ ├── faculdadevincint.png │ │ ├── fanhero.png │ │ ├── idopterlabs.png │ │ └── jetbrains.png │ ├── networking.png │ ├── palestras.png │ └── sorteios.png ├── locales │ ├── en │ │ └── common.json │ ├── es │ │ └── common.json │ └── pt │ │ └── common.json └── robots.txt ├── src ├── assets │ └── line-section.svg ├── components │ ├── dropdown │ │ ├── Dropdown.tsx │ │ └── styles │ │ │ └── Dropdown.module.css │ ├── events │ │ ├── CarouselButton.tsx │ │ ├── CarouselDotButton.tsx │ │ ├── EventCard.tsx │ │ ├── EventCarousel.tsx │ │ ├── EventList.tsx │ │ ├── EventLoader.tsx │ │ ├── EventSection.tsx │ │ └── index.ts │ ├── gallery │ │ ├── Gallery.tsx │ │ └── index.ts │ ├── header │ │ ├── Header.tsx │ │ └── index.ts │ ├── hero │ │ ├── Detail.tsx │ │ ├── Hero.tsx │ │ ├── ImageHero.tsx │ │ ├── index.ts │ │ └── styles │ │ │ ├── Detail.module.css │ │ │ └── ImageHero.module.css │ ├── newsletter │ │ ├── Newsletter.tsx │ │ └── index.ts │ └── section │ │ ├── Container.tsx │ │ ├── ContainerContent.tsx │ │ ├── Content.tsx │ │ ├── Image.tsx │ │ ├── Info.tsx │ │ ├── Section.tsx │ │ ├── Title.tsx │ │ ├── index.ts │ │ └── styles │ │ ├── Content.module.css │ │ ├── Image.module.css │ │ └── Title.module.css ├── contants │ ├── animationsVariants.ts │ └── seo.ts ├── contexts │ └── ThemeContext.tsx ├── data │ └── mock │ │ ├── events.ts │ │ └── gallery.ts ├── hooks │ ├── useBreakpoints.tsx │ ├── useEventFetcher.tsx │ ├── useEvents.ts │ ├── useLandingPageInfos.tsx │ └── useTheme.tsx ├── pages │ ├── _app.tsx │ ├── _document.tsx │ ├── globals.css │ └── index.tsx └── types │ ├── components │ ├── dropdownTypes.ts │ ├── eventsTypes.ts │ ├── galleryTypes.ts │ └── sectionTypes.ts │ ├── contexts │ └── themeContextTypes.ts │ └── hooks │ └── useThemeTypes.ts ├── tailwind.config.ts └── tsconfig.json /.all-contributorsrc: -------------------------------------------------------------------------------- 1 | { 2 | "files": [ 3 | "README.md" 4 | ], 5 | "imageSize": 100, 6 | "commit": false, 7 | "commitType": "docs", 8 | "commitConvention": "angular", 9 | "contributors": [ 10 | { 11 | "login": "DaywisonSilva", 12 | "name": "Daywison Silva", 13 | "avatar_url": "https://avatars.githubusercontent.com/u/54292958?v=4", 14 | "profile": "https://www.linkedin.com/in/daywison-s-ab11b6121/", 15 | "contributions": [ 16 | "review", 17 | "code", 18 | "design" 19 | ] 20 | }, 21 | { 22 | "login": "thauska", 23 | "name": "Thayana Correa Mamore", 24 | "avatar_url": "https://avatars.githubusercontent.com/u/8525721?v=4", 25 | "profile": "https://thayanacmamore.dev", 26 | "contributions": [ 27 | "review" 28 | ] 29 | }, 30 | { 31 | "login": "iagocavalcante", 32 | "name": "Iago Angelim Costa Cavalcante", 33 | "avatar_url": "https://avatars.githubusercontent.com/u/5131187?v=4", 34 | "profile": "https://iagocavalcante.com/", 35 | "contributions": [ 36 | "review" 37 | ] 38 | }, 39 | { 40 | "login": "suamirochadev", 41 | "name": "Suami Rocha", 42 | "avatar_url": "https://avatars.githubusercontent.com/u/110056279?v=4", 43 | "profile": "https://bento.me/suamirochadev", 44 | "contributions": [ 45 | "code", 46 | "bug" 47 | ] 48 | }, 49 | { 50 | "login": "ecsistem", 51 | "name": "Edson Costa", 52 | "avatar_url": "https://avatars.githubusercontent.com/u/61160635?v=4", 53 | "profile": "https://www.gitshowcase.com/ecsistem", 54 | "contributions": [ 55 | "code", 56 | "bug", 57 | "doc" 58 | ] 59 | }, 60 | { 61 | "login": "juanrtalmeida", 62 | "name": "Juan Rodrigues Teixeira Almeida ", 63 | "avatar_url": "https://avatars.githubusercontent.com/u/75220133?v=4", 64 | "profile": "https://github.com/juanrtalmeida", 65 | "contributions": [ 66 | "code", 67 | "bug", 68 | "translation" 69 | ] 70 | }, 71 | { 72 | "login": "ThiagoFigueiroRibeiro", 73 | "name": "Thiago Figueiró Ribeiro", 74 | "avatar_url": "https://avatars.githubusercontent.com/u/8943388?v=4", 75 | "profile": "https://thiagofigueiroribeiro.github.io/", 76 | "contributions": [ 77 | "bug", 78 | "doc", 79 | "code" 80 | ] 81 | }, 82 | { 83 | "login": "cleisoncarlos", 84 | "name": "Cleison Carlos", 85 | "avatar_url": "https://avatars.githubusercontent.com/u/5004792?v=4", 86 | "profile": "http://www.cleisoncarlos.com", 87 | "contributions": [ 88 | "code" 89 | ] 90 | }, 91 | { 92 | "login": "ruanvalente", 93 | "name": "Ruan Valente", 94 | "avatar_url": "https://avatars.githubusercontent.com/u/6674232?v=4", 95 | "profile": "https://www.linkedin.com/in/ruan-valente", 96 | "contributions": [ 97 | "code" 98 | ] 99 | }, 100 | { 101 | "login": "Kenny4297", 102 | "name": "Kedgard Cordero", 103 | "avatar_url": "https://avatars.githubusercontent.com/u/97119018?v=4", 104 | "profile": "https://kedgard-cordero.netlify.app", 105 | "contributions": [ 106 | "code" 107 | ] 108 | }, 109 | { 110 | "login": "tuiza", 111 | "name": "Luiza Marlene", 112 | "avatar_url": "https://avatars.githubusercontent.com/u/84198233?v=4", 113 | "profile": "http://www.linkedin.com/in/luizamarlene", 114 | "contributions": [ 115 | "code" 116 | ] 117 | }, 118 | { 119 | "login": "lubien", 120 | "name": "Lubien", 121 | "avatar_url": "https://avatars.githubusercontent.com/u/9121359?v=4", 122 | "profile": "https://lubien.dev", 123 | "contributions": [ 124 | "review" 125 | ] 126 | }, 127 | { 128 | "login": "patrickmonteiro", 129 | "name": "Patrick Monteiro", 130 | "avatar_url": "https://avatars.githubusercontent.com/u/13258255?v=4", 131 | "profile": "https://www.youtube.com/c/PatrickMonteiroEng", 132 | "contributions": [ 133 | "code" 134 | ] 135 | }, 136 | { 137 | "login": "eduuardonogueira", 138 | "name": "Eduardo Nogueira", 139 | "avatar_url": "https://avatars.githubusercontent.com/u/88352978?v=4", 140 | "profile": "https://www.linkedin.com/in/eduuardonogueira", 141 | "contributions": [ 142 | "code", 143 | "bug" 144 | ] 145 | }, 146 | { 147 | "login": "saadman-galib", 148 | "name": "Saadman Galib", 149 | "avatar_url": "https://avatars.githubusercontent.com/u/73209315?v=4", 150 | "profile": "https://saadmangalib.netlify.app/", 151 | "contributions": [ 152 | "code", 153 | "bug" 154 | ] 155 | } 156 | ], 157 | "contributorsPerLine": 7, 158 | "skipCi": true, 159 | "repoType": "github", 160 | "repoHost": "https://github.com", 161 | "projectName": "devsnorte-landing-page", 162 | "projectOwner": "devsnorte" 163 | } 164 | -------------------------------------------------------------------------------- /.eslintrc.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": [ 3 | "eslint:recommended", 4 | "next/core-web-vitals", 5 | "plugin:react/recommended", 6 | "prettier" 7 | ], 8 | "plugins": [ 9 | "prettier" 10 | ], 11 | "globals": { 12 | "React": "readonly" 13 | }, 14 | "rules": { 15 | "no-unused-vars": [ 16 | "error", 17 | { 18 | "argsIgnorePattern": "^_" 19 | } 20 | ], 21 | "react/destructuring-assignment": [ 22 | "error", 23 | "always", 24 | { 25 | "destructureInSignature": "always" 26 | } 27 | ], 28 | "react/jsx-no-leaked-render": [ 29 | "error", 30 | { 31 | "validStrategies": [ 32 | "ternary" 33 | ] 34 | } 35 | ], 36 | "react/jsx-max-depth": [ 37 | "error", 38 | { 39 | "max": 5 40 | } 41 | ], 42 | "react/function-component-definition": [ 43 | "warn", 44 | { 45 | "namedComponents": "function-declaration" 46 | } 47 | ], 48 | "react/self-closing-comp": "warn", 49 | "react/jsx-sort-props": "warn", 50 | "react/react-in-jsx-scope": "off", 51 | "react/jsx-uses-react": "off", 52 | "quotes": [ 53 | "error", 54 | "single" 55 | ], 56 | "semi": [ 57 | "error", 58 | "never" 59 | ], 60 | "react/button-has-type": "error", 61 | "react/jsx-boolean-value": 2, 62 | "react/jsx-closing-bracket-location": [ 63 | 1, 64 | "line-aligned" 65 | ], 66 | "react/jsx-props-no-spreading": [ 67 | "warn" 68 | ], 69 | "no-var": "error", 70 | "no-unreachable": "error", 71 | "no-use-before-define": "error", 72 | "dot-notation": "error", 73 | "no-empty": "error", 74 | "prefer-const": "error", 75 | "brace-style": [ 76 | "error", 77 | "1tbs", 78 | { 79 | "allowSingleLine": true 80 | } 81 | ], 82 | "no-multi-spaces": "error", 83 | "space-in-parens": "error", 84 | "space-infix-ops": "error", 85 | "object-curly-spacing": [ 86 | "error", 87 | "always" 88 | ], 89 | "max-len": [ 90 | "error", 91 | { 92 | "code": 180 93 | } 94 | ], 95 | "jsx-quotes": [ 96 | "error", 97 | "prefer-single" 98 | ] 99 | } 100 | } -------------------------------------------------------------------------------- /.github/holopin.yml: -------------------------------------------------------------------------------- 1 | organization: devsnorte 2 | defaultSticker: clw5l8ocz86670flaa1w09uio 3 | stickers: 4 | - 5 | id: clw5l8ocz86670flaa1w09uio 6 | alias: devsnorte-oss 7 | -------------------------------------------------------------------------------- /.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 | -------------------------------------------------------------------------------- /.nvmrc: -------------------------------------------------------------------------------- 1 | v20.12.1 2 | -------------------------------------------------------------------------------- /.prettierrc: -------------------------------------------------------------------------------- 1 | { 2 | "tabWidth": 2, 3 | "semi": false, 4 | "singleQuote": true, 5 | "trailingComma": "none", 6 | "printWidth": 180, 7 | "useTabs": false, 8 | "endOfLine": "auto", 9 | "jsxSingleQuote": true 10 | } -------------------------------------------------------------------------------- /.tool-versions: -------------------------------------------------------------------------------- 1 | nodejs 20.12.1 2 | -------------------------------------------------------------------------------- /.vscode/extensions.json: -------------------------------------------------------------------------------- 1 | { 2 | "recommendations": [ 3 | "bradlc.vscode-tailwindcss" 4 | ], 5 | } -------------------------------------------------------------------------------- /.vscode/settings.json: -------------------------------------------------------------------------------- 1 | { 2 | "files.associations": { 3 | "*.css": "tailwindcss" 4 | }, 5 | "workbench.colorCustomizations": { 6 | "statusBar.background": "#5ED29E", 7 | "statusBar.foreground": "#000000" 8 | }, 9 | "i18n-ally.localesPaths": ["public/locales"], 10 | "i18n-ally.keystyle": "nested" 11 | } 12 | -------------------------------------------------------------------------------- /CODE_OF_CONDUCT.md: -------------------------------------------------------------------------------- 1 | # Contributor Covenant Code of Conduct 2 | 3 | ## Our Pledge 4 | 5 | We as members, contributors, and leaders pledge to make participation in our 6 | community a harassment-free experience for everyone, regardless of age, body 7 | size, visible or invisible disability, ethnicity, sex characteristics, gender 8 | identity and expression, level of experience, education, socio-economic status, 9 | nationality, personal appearance, race, religion, or sexual identity 10 | and orientation. 11 | 12 | We pledge to act and interact in ways that contribute to an open, welcoming, 13 | diverse, inclusive, and healthy community. 14 | 15 | ## Our Standards 16 | 17 | Examples of behavior that contributes to a positive environment for our 18 | community include: 19 | 20 | * Demonstrating empathy and kindness toward other people 21 | * Being respectful of differing opinions, viewpoints, and experiences 22 | * Giving and gracefully accepting constructive feedback 23 | * Accepting responsibility and apologizing to those affected by our mistakes, 24 | and learning from the experience 25 | * Focusing on what is best not just for us as individuals, but for the 26 | overall community 27 | 28 | Examples of unacceptable behavior include: 29 | 30 | * The use of sexualized language or imagery, and sexual attention or 31 | advances of any kind 32 | * Trolling, insulting or derogatory comments, and personal or political attacks 33 | * Public or private harassment 34 | * Publishing others' private information, such as a physical or email 35 | address, without their explicit permission 36 | * Other conduct which could reasonably be considered inappropriate in a 37 | professional setting 38 | 39 | ## Enforcement Responsibilities 40 | 41 | Community leaders are responsible for clarifying and enforcing our standards of 42 | acceptable behavior and will take appropriate and fair corrective action in 43 | response to any behavior that they deem inappropriate, threatening, offensive, 44 | or harmful. 45 | 46 | Community leaders have the right and responsibility to remove, edit, or reject 47 | comments, commits, code, wiki edits, issues, and other contributions that are 48 | not aligned to this Code of Conduct, and will communicate reasons for moderation 49 | decisions when appropriate. 50 | 51 | ## Scope 52 | 53 | This Code of Conduct applies within all community spaces, and also applies when 54 | an individual is officially representing the community in public spaces. 55 | Examples of representing our community include using an official e-mail address, 56 | posting via an official social media account, or acting as an appointed 57 | representative at an online or offline event. 58 | 59 | ## Enforcement 60 | 61 | Instances of abusive, harassing, or otherwise unacceptable behavior may be 62 | reported to the community leaders responsible for enforcement at 63 | devsnorte@gmail.com. 64 | All complaints will be reviewed and investigated promptly and fairly. 65 | 66 | All community leaders are obligated to respect the privacy and security of the 67 | reporter of any incident. 68 | 69 | ## Enforcement Guidelines 70 | 71 | Community leaders will follow these Community Impact Guidelines in determining 72 | the consequences for any action they deem in violation of this Code of Conduct: 73 | 74 | ### 1. Correction 75 | 76 | **Community Impact**: Use of inappropriate language or other behavior deemed 77 | unprofessional or unwelcome in the community. 78 | 79 | **Consequence**: A private, written warning from community leaders, providing 80 | clarity around the nature of the violation and an explanation of why the 81 | behavior was inappropriate. A public apology may be requested. 82 | 83 | ### 2. Warning 84 | 85 | **Community Impact**: A violation through a single incident or series 86 | of actions. 87 | 88 | **Consequence**: A warning with consequences for continued behavior. No 89 | interaction with the people involved, including unsolicited interaction with 90 | those enforcing the Code of Conduct, for a specified period of time. This 91 | includes avoiding interactions in community spaces as well as external channels 92 | like social media. Violating these terms may lead to a temporary or 93 | permanent ban. 94 | 95 | ### 3. Temporary Ban 96 | 97 | **Community Impact**: A serious violation of community standards, including 98 | sustained inappropriate behavior. 99 | 100 | **Consequence**: A temporary ban from any sort of interaction or public 101 | communication with the community for a specified period of time. No public or 102 | private interaction with the people involved, including unsolicited interaction 103 | with those enforcing the Code of Conduct, is allowed during this period. 104 | Violating these terms may lead to a permanent ban. 105 | 106 | ### 4. Permanent Ban 107 | 108 | **Community Impact**: Demonstrating a pattern of violation of community 109 | standards, including sustained inappropriate behavior, harassment of an 110 | individual, or aggression toward or disparagement of classes of individuals. 111 | 112 | **Consequence**: A permanent ban from any sort of public interaction within 113 | the community. 114 | 115 | ## Attribution 116 | 117 | This Code of Conduct is adapted from the [Contributor Covenant][homepage], 118 | version 2.0, available at 119 | https://www.contributor-covenant.org/version/2/0/code_of_conduct.html. 120 | 121 | Community Impact Guidelines were inspired by [Mozilla's code of conduct 122 | enforcement ladder](https://github.com/mozilla/diversity). 123 | 124 | [homepage]: https://www.contributor-covenant.org 125 | 126 | For answers to common questions about this code of conduct, see the FAQ at 127 | https://www.contributor-covenant.org/faq. Translations are available at 128 | https://www.contributor-covenant.org/translations. 129 | -------------------------------------------------------------------------------- /CONTRIBUTING.md: -------------------------------------------------------------------------------- 1 | # Contribuindo para a Página da comunidade Devs Norte 2 | 3 | Agradecemos por considerar contribuir para este projeto! Seu apoio é fundamental para tornar este projeto melhor para todos. Aqui estão algumas diretrizes que gostaríamos que você seguisse para facilitar o processo de contribuição. 4 | 5 | ## Como contribuir 6 | 7 | 1. Faça um fork do repositório e clone-o localmente. 8 | 2. Crie uma nova branch para sua contribuição: `git checkout -b nome-da-sua-branch`. 9 | 3. Faça suas alterações. 10 | 4. Teste suas alterações localmente para garantir que tudo está funcionando conforme o esperado. 11 | 5. Certifique-se de seguir as convenções de codificação e estilo do projeto. 12 | 6. Faça commit das suas alterações: `git commit -m 'Descrição do commit'`. 13 | 7. Faça push para a branch: `git push origin nome-da-sua-branch`. 14 | 8. Abra uma pull request para revisão para `devsnorte:main`. 15 | 16 | ## Diretrizes de Pull Request 17 | 18 | - Certifique-se de que sua pull request está relacionada a uma issue existente. Se não estiver, crie uma nova issue antes de enviar a pull request. 19 | - Seja claro e conciso em suas descrições. 20 | - Certifique-se de que seus commits estejam bem estruturados e descritos. Recomendamos que siga a [convenção de commits](https://www.conventionalcommits.org/pt-br/v1.0.0-beta.4/). 21 | 22 | ## Abertura de Issues 23 | 24 | Antes de criar uma nova issue, por favor, pesquise as já abertas usando a [barra de busca de issues do GitHub](https://docs.github.com/en/issues/tracking-your-work-with-issues/filtering-and-searching-issues-and-pull-requests). Você pode encontrar a solução para o seu problema, ou verificar se é um problema já conhecido. 25 | 26 | Queremos um projeto livre de bugs e com o melhor desempenho possível. Por isso, levamos todas as issues reportadas a sério. Mas por favor, esteja ciente de que se não conseguirmos reproduzir o problema, não teremos como localizá-lo e corrigi-lo adequadamente. 27 | 28 | Portanto, para resolver o problema da melhor maneira possível, por favor, crie um repositório mínimo que reproduza o problema com o menor código possível explicando e demonstrando o erro. 29 | 30 | Sem informações suficientes para reproduzir o problema, nós iremos fechá-lo porque não podemos recreá-lo e resolvê-lo. 31 | 32 | ## Diretrizes de estilo de código 33 | 34 | - Siga as convenções de codificação do projeto. 35 | - Mantenha o código claro e legível. 36 | - Comente seu código, quando necessário, para explicar decisões de design ou partes complexas do código. 37 | 38 | ## Licença 39 | 40 | Ao contribuir para este projeto, você concorda que suas contribuições serão licenciadas de acordo com a [Licença do Projeto](https://github.com/devsnorte/devsnorte-landing-page/blob/main/LICENSE.md). 41 | 42 | Agradecemos novamente por contribuir! 43 | -------------------------------------------------------------------------------- /LICENSE.md: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2024 Devs Norte 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Landing Page - Comunidade Devs Norte 2 | 3 | [![All Contributors](https://img.shields.io/badge/all_contributors-15-orange.svg?style=flat-square)](#contributors-) 4 | 5 | 6 | ![Logo da Comunidade Devs Norte](https://imgur.com/0OLFKkZ.png) 7 | 8 | Bem-vindo à Landing Page da Comunidade Devs Norte! 9 | 10 | ## Sobre Nós 11 | 12 | A Devs Norte é uma comunidade dedicada a reunir desenvolvedores de software do Norte do Brasil. Nosso objetivo é promover a colaboração, o aprendizado e o networking entre profissionais de tecnologia da região. 13 | 14 | ## Recursos 15 | 16 | - **Eventos**: Fique por dentro dos próximos eventos da comunidade, incluindo meetups, workshops, webinars e hackathons. 17 | 18 | - **Recursos**: Descubra uma variedade de recursos úteis para desenvolvedores, como tutoriais, cursos, ferramentas e bibliotecas. 19 | 20 | - **Fórum**: Participe de discussões, faça perguntas, compartilhe conhecimento e obtenha suporte em nosso fórum dedicado. 21 | 22 | ## Tecnologias Utilizadas 23 | 24 | Este site foi desenvolvido utilizando o framework Next.js versão 14, uma poderosa ferramenta para construção de aplicações web modernas e otimizadas. 25 | 26 | ## Deploy 27 | 28 | O site está disponível para visualização em [devsnorte.netlify.app](https://devsnorte.netlify.app/). 29 | 30 | ## O que é necessário antes da instalação 31 | 32 | Você precisa ter o Node.js e o NPM (Node Package Manager) instalados para rodar a aplicação. 33 | 34 | ### Instalação Linux 35 | No terminal, rode os seguintes comandos: 36 | ```bash 37 | sudo apt update 38 | sudo apt install nodejs 39 | ``` 40 | 41 | ### Instalação Windows 42 | Instale a versão mais recente no link a seguir: 43 | ```bash 44 | https://nodejs.org/en/download/ 45 | ``` 46 | Ele já instala o NPM junto com o Node.js. 47 | 48 | ### Para verificar se a instalação deu certo, rode: 49 | ```bash 50 | node --version 51 | npm --version 52 | ``` 53 | Devem aparecer as versões do Node.js e do npm na sua linha de comando. 54 | 55 | ## Como Instalar 56 | 57 | Para instalar e rodar o projeto localmente, siga estes passos: 58 | 59 | 1. Clone o repositório: 60 | 61 | ```bash 62 | git clone https://github.com/devsnorte/devsnorte-landing-page.git 63 | ``` 64 | 65 | 2. Acesse o diretório do projeto: 66 | 67 | ```bash 68 | cd devsnorte-landing-page 69 | ``` 70 | 71 | 3. Instale as dependências: 72 | 73 | ```bash 74 | npm install 75 | # ou 76 | yarn install 77 | ``` 78 | 79 | ## Como Rodar 80 | 81 | Para iniciar o servidor de desenvolvimento, utilize o seguinte comando: 82 | 83 | ```bash 84 | npm run dev 85 | # ou 86 | yarn dev 87 | ``` 88 | 89 | ## Layout 90 | 91 | O layout do site está disponível no Figma para visualização e contribuições. Você pode acessá-lo [aqui](https://www.figma.com/file/eenBVFzu17zB259Xw6OUwu/Devs-Norte---Site-Redesign?type=design&node-id=31%3A173&mode=design&t=WJTjULmKOs3K9chc-1). 92 | 93 | ## Contribuições 94 | 95 | - Veja o [Contributing.md](https://github.com/devsnorte/devsnorte-landing-page/blob/main/CONTRIBUTING.md) para mais informações sobre como contribuir! 96 | 97 | ## Como Fazer Commit 98 | 99 | Para padronizar as mensagens de commit, recomendamos o uso da ferramenta `git-cz` em conjunto com a padronização Conventional Commits. Siga os passos abaixo para utilizá-la: 100 | 101 | 1. Certifique-se de estar no diretório do projeto. 102 | 103 | 2. Execute o seguinte comando para fazer um commit: 104 | 105 | ```bash 106 | npm run commit 107 | ``` 108 | 109 | ## Contato 110 | 111 | Para mais informações ou dúvidas, entre em contato conosco ou siga-nos nas redes sociais: 112 | 113 | - Discord: [Devs Norte](https://discord.gg/V825KxKzcQ) 114 | - Instagram: [@devsnorte](https://instagram.com/devsnorte) 115 | - Twitter: [@devsnorte](https://twitter.com/devsnorte) 116 | - YouTube: [Devs Norte](https://www.youtube.com/c/DevsNorte) 117 | 118 | Estamos ansiosos para conhecer você e tornar nossa comunidade ainda mais incrível juntos! 🚀 119 | 120 | ## Licença 121 | 122 | Este projeto é licenciado sob os termos da [Licença MIT](LICENSE.md). 123 | 124 | ## Código de Conduta 125 | 126 | Por favor, consulte o nosso [Código de Conduta](CODE_OF_CONDUCT.md) para entender nossas diretrizes de comportamento e as medidas a serem tomadas em caso de violação. 127 | 128 | ## Contribuidores ✨ 129 | 130 | Thanks goes to these wonderful people ([emoji key](https://allcontributors.org/docs/en/emoji-key)): 131 | 132 | 133 | 134 | 135 | 136 | 137 | 138 | 139 | 140 | 141 | 142 | 143 | 144 | 145 | 146 | 147 | 148 | 149 | 150 | 151 | 152 | 153 | 154 | 155 | 156 | 157 | 158 | 159 |
Daywison Silva
Daywison Silva

👀 💻 🎨
Thayana Correa Mamore
Thayana Correa Mamore

👀
Iago Angelim Costa Cavalcante
Iago Angelim Costa Cavalcante

👀
Suami Rocha
Suami Rocha

💻 🐛
Edson Costa
Edson Costa

💻 🐛 📖
Juan Rodrigues Teixeira Almeida
Juan Rodrigues Teixeira Almeida

💻 🐛 🌍
Thiago Figueiró Ribeiro
Thiago Figueiró Ribeiro

🐛 📖 💻
Cleison Carlos
Cleison Carlos

💻
Ruan Valente
Ruan Valente

💻
Kedgard Cordero
Kedgard Cordero

💻
Luiza Marlene
Luiza Marlene

💻
Lubien
Lubien

👀
Patrick Monteiro
Patrick Monteiro

💻
Eduardo Nogueira
Eduardo Nogueira

💻 🐛
Saadman Galib
Saadman Galib

💻 🐛
160 | 161 | 162 | 163 | 164 | 165 | 166 | This project follows the [all-contributors](https://github.com/all-contributors/all-contributors) specification. Contributions of any kind welcome! 167 | 168 | --- 169 |

170 | Developed with ❤️ from community to community 171 |

172 | -------------------------------------------------------------------------------- /next-i18next.config.js: -------------------------------------------------------------------------------- 1 | /** @type {import('next-i18next').UserConfig} */ 2 | module.exports = { 3 | i18n: { 4 | defaultLocale: 'en', 5 | locales: ['en', 'pt', 'es'] 6 | } 7 | } 8 | -------------------------------------------------------------------------------- /next.config.js: -------------------------------------------------------------------------------- 1 | /** @type {import('next').NextConfig} */ 2 | const { i18n } = require('./next-i18next.config') 3 | module.exports = { 4 | i18n, 5 | webpack(config) { 6 | const fileLoaderRule = config.module.rules.find((rule) => rule.test?.test?.('.svg')) 7 | 8 | config.module.rules.push( 9 | // Reapply the existing rule, but only for svg imports ending in ?url 10 | { 11 | ...fileLoaderRule, 12 | test: /\.svg$/i, 13 | resourceQuery: /url/ // *.svg?url 14 | }, 15 | // Convert all other *.svg imports to React components 16 | { 17 | test: /\.svg$/i, 18 | issuer: fileLoaderRule.issuer, 19 | resourceQuery: { not: [...fileLoaderRule.resourceQuery.not, /url/] }, // exclude if *.svg?url 20 | use: ['@svgr/webpack'] 21 | } 22 | ) 23 | 24 | // Modify the file loader rule to ignore *.svg, since we have it handled now. 25 | fileLoaderRule.exclude = /\.svg$/i 26 | 27 | return config 28 | }, 29 | images: { 30 | remotePatterns: [ 31 | { 32 | protocol: 'https', 33 | hostname: 'images.sympla.com.br' 34 | } 35 | ] 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "devsnorte-landing-page", 3 | "version": "0.1.0", 4 | "private": true, 5 | "engines": { 6 | "node": "^20" 7 | }, 8 | "scripts": { 9 | "dev": "next dev", 10 | "build": "next build", 11 | "start": "next start", 12 | "lint": "next lint", 13 | "lint:fix": "next lint --fix", 14 | "commit": "git-cz" 15 | }, 16 | "dependencies": { 17 | "@types/gsap": "^3.0.0", 18 | "embla-carousel-react": "^8.1.3", 19 | "framer-motion": "^11.0.25", 20 | "gsap": "^3.12.5", 21 | "i18next": "^23.9.0", 22 | "next": "^14.2.14", 23 | "next-i18next": "^15.2.0", 24 | "react": "^18", 25 | "react-dom": "^18", 26 | "react-i18next": "^14.0.5", 27 | "react-icons": "^5.0.1", 28 | "stringify": "^2.2.0" 29 | }, 30 | "devDependencies": { 31 | "@svgr/webpack": "^8.1.0", 32 | "@types/node": "20.16.10", 33 | "@types/react": "18.3.10", 34 | "@types/react-dom": "^18", 35 | "autoprefixer": "^10.0.1", 36 | "commitizen": "^4.3.0", 37 | "cz-conventional-changelog": "^3.3.0", 38 | "eslint": "^8", 39 | "eslint-config-next": "14.1.0", 40 | "eslint-config-prettier": "^9.1.0", 41 | "eslint-plugin-prettier": "^5.1.3", 42 | "postcss": "^8", 43 | "prettier": "^3.2.5", 44 | "tailwindcss": "^3.3.0", 45 | "typescript": "5.6.2" 46 | }, 47 | "config": { 48 | "commitizen": { 49 | "path": "./node_modules/cz-conventional-changelog" 50 | } 51 | } 52 | } 53 | -------------------------------------------------------------------------------- /postcss.config.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | plugins: { 3 | tailwindcss: {}, 4 | autoprefixer: {} 5 | } 6 | } 7 | -------------------------------------------------------------------------------- /public/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/devsnorte/devsnorte-landing-page/41cc966f7b63c67b2a53aa54fc90b54d4eeca6d1/public/favicon.ico -------------------------------------------------------------------------------- /public/icons/arrow.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /public/icons/devsnorte-hero-light.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | -------------------------------------------------------------------------------- /public/icons/devsnorte-hero.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | -------------------------------------------------------------------------------- /public/icons/dot.svg: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /public/icons/favicon.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | -------------------------------------------------------------------------------- /public/icons/line-section.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | -------------------------------------------------------------------------------- /public/icons/loading.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /public/icons/logo-light.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | -------------------------------------------------------------------------------- /public/icons/logo.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | -------------------------------------------------------------------------------- /public/icons/menu.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | -------------------------------------------------------------------------------- /public/icons/rectangle-section.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | -------------------------------------------------------------------------------- /public/icons/star.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | -------------------------------------------------------------------------------- /public/icons/translate.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /public/images/eventos.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/devsnorte/devsnorte-landing-page/41cc966f7b63c67b2a53aa54fc90b54d4eeca6d1/public/images/eventos.png -------------------------------------------------------------------------------- /public/images/logos/amazoniaonline.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/devsnorte/devsnorte-landing-page/41cc966f7b63c67b2a53aa54fc90b54d4eeca6d1/public/images/logos/amazoniaonline.png -------------------------------------------------------------------------------- /public/images/logos/faculdadevincint.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/devsnorte/devsnorte-landing-page/41cc966f7b63c67b2a53aa54fc90b54d4eeca6d1/public/images/logos/faculdadevincint.png -------------------------------------------------------------------------------- /public/images/logos/fanhero.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/devsnorte/devsnorte-landing-page/41cc966f7b63c67b2a53aa54fc90b54d4eeca6d1/public/images/logos/fanhero.png -------------------------------------------------------------------------------- /public/images/logos/idopterlabs.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/devsnorte/devsnorte-landing-page/41cc966f7b63c67b2a53aa54fc90b54d4eeca6d1/public/images/logos/idopterlabs.png -------------------------------------------------------------------------------- /public/images/logos/jetbrains.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/devsnorte/devsnorte-landing-page/41cc966f7b63c67b2a53aa54fc90b54d4eeca6d1/public/images/logos/jetbrains.png -------------------------------------------------------------------------------- /public/images/networking.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/devsnorte/devsnorte-landing-page/41cc966f7b63c67b2a53aa54fc90b54d4eeca6d1/public/images/networking.png -------------------------------------------------------------------------------- /public/images/palestras.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/devsnorte/devsnorte-landing-page/41cc966f7b63c67b2a53aa54fc90b54d4eeca6d1/public/images/palestras.png -------------------------------------------------------------------------------- /public/images/sorteios.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/devsnorte/devsnorte-landing-page/41cc966f7b63c67b2a53aa54fc90b54d4eeca6d1/public/images/sorteios.png -------------------------------------------------------------------------------- /public/locales/en/common.json: -------------------------------------------------------------------------------- 1 | { 2 | "heroSubtitle": "The largest community in northern Brazil", 3 | "networking": "Networking", 4 | "networkingSubtitle": "Technology (IT) events are excellent opportunities for networking. These events bring together people from different sectors of the industry, including developers, entrepreneurs, investors, marketing experts, designers, among others.", 5 | "giveaways": "Sweepstakes", 6 | "giveawaysSubtitle": "During events, Devs Norte holds giveaways for books, courses, and tools used by programmers. Giveaways are a fun way to engage participants and encourage participation in events. They also encourage the developer community to share even more knowledge and resources.", 7 | "lecture": "Lectures", 8 | "lectureSubtitle": "Devs Norte events are known for being excellent sources of sharing programming knowledge. Devs Norte is a community of developers that promotes events, meetups and workshops to share ideas, experiences and solutions to the challenges faced by programmers.", 9 | "events": "Events", 10 | "noEvents": "Oops! It appears there are no events available at this time. Check back later to check for new events!", 11 | "available": "Available", 12 | "closed": "Closed", 13 | "loading": "loading", 14 | "partnerships": "Partnerships", 15 | "gallery": "Gallery", 16 | "stayUpdated": "Stay updated on the latest news", 17 | "exclusiveContent": "Receive exclusive content directly in your inbox! Subscribe to our newsletter and stay updated on the latest community news. Sign up now!", 18 | "subscribe": "Subscribe", 19 | "fullName": "Full name", 20 | "email": "E-mail" 21 | } -------------------------------------------------------------------------------- /public/locales/es/common.json: -------------------------------------------------------------------------------- 1 | { 2 | "heroSubtitle": "La comunidad más grande del norte de Brasil", 3 | "networking": "Networking", 4 | "networkingSubtitle": "Los eventos de tecnología (TI) son excelentes oportunidades para establecer contactos. Estos eventos reúnen a personas de diferentes sectores de la industria, incluidos desarrolladores, emprendedores, inversores, especialistas en marketing, diseñadores, entre otros", 5 | "giveaways": "Sorteos", 6 | "giveawaysSubtitle": "Durante los eventos, Devs Norte realiza sorteos de libros, cursos y herramientas utilizadas por los programadores. Los sorteos son una forma divertida de involucrar a los participantes y fomentar la participación en eventos. También alientan a la comunidad de desarrolladores a compartir aún más conocimientos y recursos.", 7 | "lecture": "Discursos", 8 | "lectureSubtitle": "Los eventos de Devs Norte son conocidos por ser excelentes fuentes para compartir conocimientos de programación. Devs Norte es una comunidad de desarrolladores que promueve eventos, quedadas y talleres para compartir ideas, experiencias y soluciones a los desafíos que enfrentan los programadores.", 9 | "events": "Eventos", 10 | "noEvents": "¡Ups! Parece que no hay eventos disponibles en este momento. ¡Vuelve más tarde para comprobar si hay nuevos eventos!", 11 | "available": "Disponible", 12 | "closed": "Cerrado", 13 | "loading": "Cargando", 14 | "partnerships": "Asociaciones", 15 | "gallery": "Galería", 16 | "stayUpdated": "Mantente al día con las últimas novedades", 17 | "exclusiveContent": "Recibe contenido exclusivo directamente en tu bandeja de entrada. ¡Suscríbete a nuestro boletín y mantente actualizado sobre las últimas noticias de la comunidad. ¡Regístrate ahora!", 18 | "subscribe": "Suscribirse", 19 | "fullName": "Nombre completo", 20 | "email": "Correo electrónico" 21 | } 22 | -------------------------------------------------------------------------------- /public/locales/pt/common.json: -------------------------------------------------------------------------------- 1 | { 2 | "heroSubtitle": "A maior comunidade do norte do Brasil", 3 | "networking": "Networking", 4 | "networkingSubtitle": "Eventos de tecnologia (TI) são excelentes oportunidades para networking. Esses eventos reúnem pessoas de diversos setores da indústria, incluindo desenvolvedores, empresários, investidores, especialistas em marketing, designers, entre outros.", 5 | "giveaways": "Sorteios", 6 | "giveawaysSubtitle": "Durante os eventos, a Devs Norte realiza sorteios de livros, cursos, e ferramentas utilizadas por programadores. Os sorteios são uma forma divertida de envolver os participantes e estimular a participação nos eventos. Eles também incentivam a comunidade de desenvolvedores a compartilhar ainda mais conhecimentos e recursos.", 7 | "lecture": "Palestras", 8 | "lectureSubtitle": "Os eventos da Devs Norte são conhecidos por serem excelentes fontes de compartilhamento de conhecimento em programação. A Devs Norte é uma comunidade de desenvolvedores que promove eventos, meetups e workshops para compartilhar ideias, experiências e soluções para os desafios enfrentados pelos programadores.", 9 | "events": "Eventos", 10 | "noEvents": "Ops! Parece que não há eventos disponíveis no momento. Volte mais tarde para verificar novos eventos!", 11 | "available": "Disponíveis", 12 | "closed": "Encerrados", 13 | "loading": "Carregando", 14 | "partnerships": "Parcerias", 15 | "gallery": "Galeria", 16 | "stayUpdated": "Fique por dentro das novidades", 17 | "exclusiveContent": "Receba conteúdos exclusivos diretamente na sua caixa de entrada! Assine nossa newsletter e mantenha-se atualizado(a) sobre as novidades da comunidade. Cadastre-se agora mesmo!", 18 | "subscribe": "Inscrever-se", 19 | "fullName": "Nome completo", 20 | "email": "E-mail" 21 | } 22 | -------------------------------------------------------------------------------- /public/robots.txt: -------------------------------------------------------------------------------- 1 | User-agent: * 2 | Allow: / 3 | 4 | -------------------------------------------------------------------------------- /src/assets/line-section.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | -------------------------------------------------------------------------------- /src/components/dropdown/Dropdown.tsx: -------------------------------------------------------------------------------- 1 | 'use client' 2 | import { useEffect, useRef, useState } from 'react' 3 | import styles from './styles/Dropdown.module.css' 4 | import Arrow from '/public/icons/arrow.svg' 5 | import { DropDownProps } from '@/types/components/dropdownTypes' 6 | 7 | export function Dropdown({ data, onSelect, placeholder }: DropDownProps) { 8 | const [isOpen, setOpen] = useState(false) 9 | const ref = useRef(null) 10 | 11 | useEffect(() => { 12 | const handleClick = (e: MouseEvent) => { 13 | if (ref.current && isOpen && !ref.current.contains(e.target as Node)) { 14 | setOpen(false) 15 | } 16 | } 17 | document.addEventListener('mousedown', handleClick) 18 | return () => document.removeEventListener('click', handleClick) 19 | }, [isOpen]) 20 | 21 | const toggleDropdown = () => setOpen(!isOpen) 22 | 23 | const handleItemClick = (value: unknown) => { 24 | onSelect(value) 25 | setOpen(false) 26 | } 27 | 28 | return ( 29 |
30 |
31 | {placeholder} 32 | 33 |
34 | {isOpen ? ( 35 |
36 | {data.map((item) => ( 37 |
handleItemClick(item.value)}> 38 | {item.label} 39 |
40 | ))} 41 |
42 | ) : null} 43 |
44 | ) 45 | } 46 | -------------------------------------------------------------------------------- /src/components/dropdown/styles/Dropdown.module.css: -------------------------------------------------------------------------------- 1 | .dropdown { 2 | @apply border border-black relative z-20 w-fit bg-brand; 3 | } 4 | 5 | .dropdownPlaceholder { 6 | @apply cursor-pointer flex justify-between items-center text-black; 7 | } 8 | 9 | .header { 10 | @apply p-3.5 cursor-pointer flex justify-between items-center; 11 | } 12 | 13 | @keyframes opacity { 14 | 0% { 15 | opacity: 0; 16 | transform: translateY(10px); 17 | } 18 | 100% { 19 | opacity: 1; 20 | transform: translateY(0); 21 | } 22 | } 23 | 24 | .body { 25 | @apply p-1.5 mt-2.5 absolute top-full flex flex-col animate-[opacity_0.6s_ease-in-out] bg-brand; 26 | } 27 | 28 | .dropdownItem { 29 | @apply p-2.5 text-black border-b-black border-b last-of-type:border-b-0 cursor-pointer min-w-40; 30 | } 31 | 32 | .icon { 33 | @apply rotate-180 w-2.5 h-2.5 transition-all ease-in-out duration-200 text-black; 34 | } 35 | 36 | .icon.open { 37 | @apply rotate-90; 38 | } 39 | -------------------------------------------------------------------------------- /src/components/events/CarouselButton.tsx: -------------------------------------------------------------------------------- 1 | interface ICarouselButton { 2 | children: React.ReactNode 3 | classname?: string | undefined 4 | disabled: boolean 5 | onClick: () => void 6 | } 7 | 8 | export function CarouselButton({ children, classname, onClick, disabled }: ICarouselButton) { 9 | return ( 10 | 13 | ) 14 | } 15 | -------------------------------------------------------------------------------- /src/components/events/CarouselDotButton.tsx: -------------------------------------------------------------------------------- 1 | interface IDotButton { 2 | children?: React.ReactNode 3 | classname?: string | undefined 4 | onClick: () => void 5 | } 6 | 7 | export function DotButton({ children, classname, onClick }: IDotButton) { 8 | return ( 9 | 12 | ) 13 | } 14 | -------------------------------------------------------------------------------- /src/components/events/EventCard.tsx: -------------------------------------------------------------------------------- 1 | import { Event } from '@/types/components/eventsTypes' 2 | import Image from 'next/image' 3 | import Link from 'next/link' 4 | 5 | export function EventCard({ event }: { event: Event }) { 6 | return ( 7 | 8 |
9 |
10 | Imagem do Evento 11 |
12 |
13 |
14 |
{event.name}
15 |
{event.location.city}
16 |
17 |
18 |

{event.end_date_formats.pt}

19 |
20 |
21 |
22 | 23 | ) 24 | } 25 | -------------------------------------------------------------------------------- /src/components/events/EventCarousel.tsx: -------------------------------------------------------------------------------- 1 | import embla from 'embla-carousel-react' 2 | import { EmblaOptionsType } from 'embla-carousel' 3 | import { CarouselButton } from './CarouselButton' 4 | import { DotButton } from './CarouselDotButton' 5 | import { useEffect, useState } from 'react' 6 | import ArrowIcon from '/public/icons/arrow.svg' 7 | import DotIcon from '/public/icons/dot.svg' 8 | 9 | interface IEventCarousel { 10 | options?: EmblaOptionsType 11 | children: React.ReactNode 12 | } 13 | 14 | export function EventCarousel({ options, children }: IEventCarousel) { 15 | const [currentIndex, setCurrentIndex] = useState(options?.startIndex || 0) 16 | const [emblaRef, carousel] = embla(options) 17 | 18 | const disableNextButton = (carousel ? carousel.slideNodes().length - 1 : 0) <= currentIndex 19 | 20 | useEffect(() => { 21 | carousel?.on('init', () => { 22 | carousel.scrollTo(currentIndex) 23 | }) 24 | 25 | carousel?.on('select', () => { 26 | setCurrentIndex(carousel.selectedScrollSnap()) 27 | }) 28 | 29 | return () => { 30 | carousel?.off('select', () => null) 31 | } 32 | }, [carousel, currentIndex]) 33 | 34 | useEffect(() => { 35 | carousel?.reInit() 36 | }, [carousel]) 37 | 38 | function handleScrollTo(index: number) { 39 | setCurrentIndex(index) 40 | carousel?.scrollTo(index) 41 | } 42 | 43 | return ( 44 |
45 |
46 |
{children}
47 |
48 |
49 | handleScrollTo(currentIndex - 1)}> 50 | 51 | 52 | 53 |
54 | {carousel?.slideNodes().map((_, index) => ( 55 | handleScrollTo(index)}> 56 | 60 | 61 | ))} 62 |
63 | 64 | handleScrollTo(currentIndex + 1)}> 65 | 66 | 67 |
68 |
69 | ) 70 | } 71 | -------------------------------------------------------------------------------- /src/components/events/EventList.tsx: -------------------------------------------------------------------------------- 1 | import { EventListProps } from '@/types/components/eventsTypes' 2 | import { EventCard } from './EventCard' 3 | 4 | export function EventList({ events }: EventListProps) { 5 | return ( 6 |
7 | {events.map((event, index) => ( 8 | 9 | ))} 10 |
11 | ) 12 | } 13 | -------------------------------------------------------------------------------- /src/components/events/EventLoader.tsx: -------------------------------------------------------------------------------- 1 | 'use client' 2 | 3 | import { useTranslation } from 'react-i18next' 4 | import LoadingIcon from '/public/icons/loading.svg' 5 | import { useEffect, useState } from 'react' 6 | 7 | export function EventLoader() { 8 | const { t } = useTranslation() 9 | const [ isClient, setIsClient ] = useState(false) 10 | 11 | useEffect(() => setIsClient(true), []) 12 | 13 | return ( 14 |
15 |

{isClient ? t('loading') : null}

16 | 17 |
18 | ) 19 | } -------------------------------------------------------------------------------- /src/components/events/EventSection.tsx: -------------------------------------------------------------------------------- 1 | 'use client' 2 | 3 | import { EventType, useEvents } from '@/hooks/useEvents' 4 | import { useTranslation } from 'react-i18next' 5 | import { EventLoader } from './EventLoader' 6 | import { EventCarousel } from './EventCarousel' 7 | import { EventCard } from './EventCard' 8 | import { useEffect, useState } from 'react' 9 | import { Event } from '@/types/components/eventsTypes' 10 | 11 | interface IEventsContent { 12 | events: Event[] | undefined 13 | isLoading: boolean 14 | isClient: boolean 15 | } 16 | 17 | function EventContent({ events, isLoading, isClient }: IEventsContent) { 18 | const { t } = useTranslation() 19 | 20 | if (isLoading) return 21 | 22 | return ( 23 |
24 | {!events || events.length === 0 ? ( 25 |

{isClient ? t('noEvents') : null}

26 | ) : ( 27 | 28 | {events.map((event, index) => ( 29 | 30 | ))} 31 | 32 | )} 33 |
34 | ) 35 | } 36 | 37 | export function EventSection() { 38 | const { t } = useTranslation() 39 | const [events, setEvents] = useState() 40 | const [eventType, setEventType] = useState('future') 41 | const [isLoading, setIsLoading] = useState(true) 42 | const [isClient, setIsClient] = useState(false) 43 | const getEvents = useEvents() 44 | 45 | useEffect(() => { 46 | async function fetch() { 47 | try { 48 | const data = await getEvents(eventType) 49 | if (data) setEvents(data) 50 | } catch { 51 | /* Empty */ 52 | } finally { 53 | setIsLoading(false) 54 | } 55 | } 56 | setIsClient(true) 57 | setIsLoading(true) 58 | fetch() 59 | // eslint-disable-next-line react-hooks/exhaustive-deps 60 | }, [eventType]) 61 | 62 | return ( 63 |
64 |
65 | 72 | 79 |
80 | 81 | 82 |
83 | ) 84 | } 85 | -------------------------------------------------------------------------------- /src/components/events/index.ts: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/devsnorte/devsnorte-landing-page/41cc966f7b63c67b2a53aa54fc90b54d4eeca6d1/src/components/events/index.ts -------------------------------------------------------------------------------- /src/components/gallery/Gallery.tsx: -------------------------------------------------------------------------------- 1 | import { useEffect, useState } from 'react' 2 | import { GalleryProps } from '@/types/components/galleryTypes' 3 | import { useTranslation } from 'next-i18next' 4 | import Image from 'next/image' 5 | // import LineSection from '../../../public/icons/line-section.svg' 6 | import { Title } from '../section' 7 | import { motion, AnimatePresence } from 'framer-motion' 8 | 9 | function Gallery({ images }: GalleryProps) { 10 | const { t } = useTranslation() 11 | const [windowWidth, setWindowWidth] = useState(0) 12 | 13 | useEffect(() => { 14 | const handleResize = () => { 15 | setWindowWidth(window.innerWidth) 16 | } 17 | 18 | handleResize() // Define a largura inicial da janela 19 | window.addEventListener('resize', handleResize) 20 | 21 | return () => { 22 | window.removeEventListener('resize', handleResize) 23 | } 24 | }, []) 25 | 26 | const calculateGroups = (windowWidth: number) => (windowWidth < 1024 ? 3 : 6) 27 | 28 | const imageGroups = images.reduce((acc: string[][], image, index) => { 29 | const groupIndex = Math.floor(index / calculateGroups(windowWidth)) 30 | acc[groupIndex] = [...(acc[groupIndex] || []), image] 31 | return acc 32 | }, []) 33 | 34 | //* Testing out modal 35 | 36 | const [isModalOpen, setIsModalOpen] = useState(false) 37 | const [currentImage, setCurrentImage] = useState(0) 38 | const [currentGroup, setCurrentGroup] = useState(0) 39 | 40 | const openModal = (groupIndex: number, imageIndex: number) => { 41 | setCurrentGroup(groupIndex) 42 | setCurrentImage(imageIndex) 43 | setIsModalOpen(true) 44 | } 45 | 46 | const closeModal = () => { 47 | setIsModalOpen(false) 48 | } 49 | 50 | const goToNextImage = () => { 51 | // Check if next image is in the current group 52 | if (currentImage < imageGroups[currentGroup].length - 1) { 53 | setCurrentImage(currentImage + 1) 54 | } else if (currentGroup < imageGroups.length - 1) { 55 | // Move to the next group 56 | setCurrentGroup(currentGroup + 1) 57 | setCurrentImage(0) 58 | } 59 | } 60 | 61 | const goToPreviousImage = () => { 62 | if (currentImage > 0) { 63 | setCurrentImage(currentImage - 1) 64 | } else if (currentGroup > 0) { 65 | // Move to the previous group 66 | setCurrentGroup(currentGroup - 1) 67 | setCurrentImage(imageGroups[currentGroup - 1].length - 1) 68 | } 69 | } 70 | 71 | return ( 72 |
73 |
74 | {t('gallery')} 75 |
{/* */}
76 |
77 |
78 | {imageGroups.map((group, groupIndex) => ( 79 |
80 | {group.map((image, index) => ( 81 |
openModal(groupIndex, index)}> 82 | {`Gallery 83 |
84 | ))} 85 |
86 | ))} 87 |
88 | 89 | {isModalOpen ? ( 90 | 95 | e.stopPropagation()} 101 | > 102 | 107 | × 108 | 109 | Modal Image 117 |
118 | {!(currentImage === 0 && currentGroup === 0) ? ( 119 | 122 | ) : ( 123 |
// This div ensures the spacing remains consistent 124 | )} 125 | {!(currentImage === imageGroups[currentGroup].length - 1 && currentGroup === imageGroups.length - 1) ? ( 126 | 129 | ) : ( 130 |
// This div ensures the spacing remains consistent 131 | )} 132 |
133 |
134 |
135 | ) : null} 136 |
137 |
138 | ) 139 | } 140 | 141 | export default Gallery 142 | -------------------------------------------------------------------------------- /src/components/gallery/index.ts: -------------------------------------------------------------------------------- 1 | import Gallery from './Gallery' 2 | 3 | export default Gallery 4 | -------------------------------------------------------------------------------- /src/components/header/Header.tsx: -------------------------------------------------------------------------------- 1 | import Image from 'next/image' 2 | import Link from 'next/link' 3 | import { Dropdown } from '@/components/dropdown/Dropdown' 4 | import { useRouter } from 'next/router' 5 | import Translate from '/public/icons/translate.svg' 6 | import { useLandingPageInfos } from '@/hooks/useLandingPageInfos' 7 | import { useState } from 'react' 8 | import { useTheme } from '@/hooks/useTheme' 9 | import { CiMenuFries } from 'react-icons/ci' 10 | import { AnimatePresence, motion } from 'framer-motion' 11 | import { IoIosCloseCircleOutline } from 'react-icons/io' 12 | import { PiMoonLight, PiSunDim } from 'react-icons/pi' 13 | import { headerMenuItem, headerMenuList } from '@/contants/animationsVariants' 14 | 15 | export function Header() { 16 | const [menuOpen, setMenuOpen] = useState(false) 17 | const router = useRouter() 18 | const sections = useLandingPageInfos() 19 | const onSelectLanguage = (value: string) => { 20 | router.push(router.pathname, router.asPath, { locale: value }) 21 | } 22 | const { theme, toggleTheme } = useTheme() 23 | 24 | const scrollToSection = (sectionId: string) => { 25 | const section = document.getElementById(sectionId) 26 | if (section) { 27 | window.scrollTo({ 28 | top: section.offsetTop, 29 | behavior: 'smooth' 30 | }) 31 | } 32 | } 33 | 34 | return ( 35 |
36 | 37 |
38 | 39 |
40 | {theme === 'dark' ? ( 41 | devs norte logo 42 | ) : ( 43 | devs norte logo 44 | )} 45 | 46 | 47 |
48 |
{theme === 'light' ? : }
49 | 50 |
51 | setMenuOpen(true)} /> 52 |
53 |
54 | 55 | 56 | {menuOpen ? ( 57 | 58 | 59 | 66 |
setMenuOpen(false)}> 67 | 68 |
69 | 70 | onSelectLanguage(value as string)} 77 | placeholder={} 78 | /> 79 | 80 | {sections.map((section) => ( 81 | { 85 | setMenuOpen(false) 86 | scrollToSection(section.title) 87 | }} 88 | variants={headerMenuItem} 89 | > 90 | {section.title} 91 | 92 | ))} 93 |
94 |
95 |
96 | ) : null} 97 |
98 |
99 |
100 | ) 101 | } 102 | -------------------------------------------------------------------------------- /src/components/header/index.ts: -------------------------------------------------------------------------------- 1 | export { Header } from './Header' 2 | -------------------------------------------------------------------------------- /src/components/hero/Detail.tsx: -------------------------------------------------------------------------------- 1 | import styles from './styles/Detail.module.css' 2 | export function Detail() { 3 | return
4 | } 5 | -------------------------------------------------------------------------------- /src/components/hero/Hero.tsx: -------------------------------------------------------------------------------- 1 | 'use client' 2 | import gsap from 'gsap' 3 | import { ImageHero } from './ImageHero' 4 | import { Detail } from './Detail' 5 | import { useEffect, useRef } from 'react' 6 | import { useTranslation } from 'next-i18next' 7 | 8 | export function Hero() { 9 | const { t } = useTranslation() 10 | const textHeroSubtitleRef = useRef(null) 11 | 12 | useEffect(() => { 13 | const textHeroSubtitle = textHeroSubtitleRef.current 14 | 15 | gsap.fromTo( 16 | textHeroSubtitle, 17 | { 18 | opacity: 0, 19 | duration: 3, 20 | y: 0 21 | }, 22 | { 23 | opacity: 1, 24 | duration: 2, 25 | y: 20, 26 | ease: 'power4.out' 27 | } 28 | ) 29 | }, []) 30 | 31 | return ( 32 |
33 |
34 | 35 | 36 |

37 | {t('heroSubtitle')} 38 |

39 |
40 | 41 |
42 | ) 43 | } 44 | -------------------------------------------------------------------------------- /src/components/hero/ImageHero.tsx: -------------------------------------------------------------------------------- 1 | import { useContext } from 'react' 2 | import styles from './styles/ImageHero.module.css' 3 | import DevsNorte from '/public/icons/devsnorte-hero.svg' 4 | import DevsNorteLight from '/public/icons/devsnorte-hero-light.svg' 5 | import Star from '/public/icons/star.svg' 6 | import { ThemeContext } from '../../contexts/ThemeContext' 7 | 8 | export function ImageHero() { 9 | const { theme } = useContext(ThemeContext) 10 | return ( 11 |
12 | {theme === 'dark' ? : } 13 | 14 | 15 |
16 | ) 17 | } 18 | -------------------------------------------------------------------------------- /src/components/hero/index.ts: -------------------------------------------------------------------------------- 1 | export { Hero } from './Hero' 2 | -------------------------------------------------------------------------------- /src/components/hero/styles/Detail.module.css: -------------------------------------------------------------------------------- 1 | .detailWrapper { 2 | @apply absolute bg-brand w-4 lg:w-10 h-28 lg:h-80 -bottom-5 lg:-bottom-24 left-0; 3 | } 4 | -------------------------------------------------------------------------------- /src/components/hero/styles/ImageHero.module.css: -------------------------------------------------------------------------------- 1 | .devsnorteSvg { 2 | width: 100%; 3 | fill-opacity: 0; 4 | stroke-width: 1px; 5 | stroke-dasharray: 600; 6 | stroke-dashoffset: 600; 7 | stroke: none; 8 | animation: devsnorte-animation 2s 1s ease-in-out alternate forwards; 9 | } 10 | 11 | @keyframes devsnorte-animation { 12 | 0% { 13 | stroke-dashoffset: 600; 14 | fill-opacity: 0; 15 | stroke: #fff; 16 | } 17 | 50% { 18 | fill-opacity: 0; 19 | } 20 | 70%, 21 | 99%, 22 | 100% { 23 | fill-opacity: 1; 24 | stroke-dashoffset: 0; 25 | } 26 | } 27 | 28 | .star { 29 | position: absolute; 30 | top: -10px; 31 | right: -10px; 32 | width: 20px; 33 | height: 20px; 34 | } 35 | -------------------------------------------------------------------------------- /src/components/newsletter/Newsletter.tsx: -------------------------------------------------------------------------------- 1 | 'use client' 2 | 3 | import { useEffect, useState } from 'react' 4 | import { useTranslation } from 'react-i18next' 5 | 6 | export function Newsletter() { 7 | const { t } = useTranslation() 8 | const [isClient, setIsClient] = useState(false) 9 | 10 | useEffect(() => { 11 | setIsClient(true) 12 | }, []) 13 | 14 | return ( 15 |
16 |
17 |
18 |

NewsLetter

19 |
20 |
{isClient ?

{t('stayUpdated')}

: null}
21 |
22 | 23 |
24 |

{isClient ? t('exclusiveContent') : null}

25 |
26 | 27 |
28 | 35 | 42 | 45 |
46 |
47 | ) 48 | } 49 | -------------------------------------------------------------------------------- /src/components/newsletter/index.ts: -------------------------------------------------------------------------------- 1 | export { Newsletter } from './Newsletter' 2 | -------------------------------------------------------------------------------- /src/components/section/Container.tsx: -------------------------------------------------------------------------------- 1 | 'use client' 2 | 3 | import { SectionContainerProps } from '@/types/components/sectionTypes' 4 | 5 | export function Container({ children, id }: SectionContainerProps) { 6 | return ( 7 |
8 | {children} 9 |
10 | ) 11 | } 12 | -------------------------------------------------------------------------------- /src/components/section/ContainerContent.tsx: -------------------------------------------------------------------------------- 1 | 'use client' 2 | 3 | import { SectionContainerContentProps } from '@/types/components/sectionTypes' 4 | 5 | export function ContainerContent({ children }: SectionContainerContentProps) { 6 | return
{children}
7 | } 8 | -------------------------------------------------------------------------------- /src/components/section/Content.tsx: -------------------------------------------------------------------------------- 1 | 'use client' 2 | import styles from './styles/Content.module.css' 3 | import { SectionContentProps } from '@/types/components/sectionTypes' 4 | 5 | const variantsClasses = { 6 | brand: 'bg-brand text-[#000]', 7 | black: 'bg-zinc-50 text-black dark:bg-[#000] dark:text-white' 8 | } 9 | 10 | export function Content({ variant = 'brand', children }: SectionContentProps) { 11 | return
{children}
12 | } 13 | -------------------------------------------------------------------------------- /src/components/section/Image.tsx: -------------------------------------------------------------------------------- 1 | 'use client' 2 | 3 | import { SectionImageProps } from '@/types/components/sectionTypes' 4 | import NextImage from 'next/image' 5 | import styles from './styles/Image.module.css' 6 | export function Image({ className, width = 768, height = 835, ...rest }: SectionImageProps) { 7 | return ( 8 | 15 | ) 16 | } 17 | -------------------------------------------------------------------------------- /src/components/section/Info.tsx: -------------------------------------------------------------------------------- 1 | 'use client' 2 | 3 | import { TextProps } from '@/types/components/sectionTypes' 4 | export function Info({ children }: TextProps) { 5 | return
{children}
6 | } 7 | -------------------------------------------------------------------------------- /src/components/section/Section.tsx: -------------------------------------------------------------------------------- 1 | 'use client' 2 | import { Container, ContainerContent, Content, Image, Info, Title } from './index' 3 | import ReactangleSection from '/public/icons/rectangle-section.svg' 4 | import LineSection from '/public/icons/line-section.svg' 5 | import { useLandingPageInfos } from '@/hooks/useLandingPageInfos' 6 | import { useBreakpoints } from '@/hooks/useBreakpoints' 7 | 8 | const Section = { 9 | Container, 10 | Content, 11 | Title, 12 | Info, 13 | Image, 14 | ContainerContent 15 | } 16 | 17 | export function SectionPrincipal() { 18 | const landingPageInfos = useLandingPageInfos() 19 | const { isCustomBreakpoint } = useBreakpoints() 20 | const shouldSquareAppear = isCustomBreakpoint(850) 21 | 22 | return landingPageInfos.map((section, index) => { 23 | const isEven = index % 2 === 0 24 | return ( 25 | 26 | {!section.customSection ? ( 27 | <> 28 | 29 | 30 | {section.title} 31 |
32 | 33 |
34 | 35 | {section.info} 36 | 37 | {shouldSquareAppear ? ( 38 | 39 | ) : null} 40 |
41 | 42 | ) : ( 43 | section.customSection 44 | )} 45 |
46 | ) 47 | }) 48 | } 49 | -------------------------------------------------------------------------------- /src/components/section/Title.tsx: -------------------------------------------------------------------------------- 1 | 'use client' 2 | 3 | import { TitleProps } from '@/types/components/sectionTypes' 4 | import { useRef } from 'react' 5 | import { useInView } from 'framer-motion' 6 | import styles from './styles/Title.module.css' 7 | 8 | export function Title({ children }: TitleProps) { 9 | const textRef = useRef(null) 10 | const isInView = useInView(textRef, { once: true, margin: '0px 100px -100px 0px' }) 11 | 12 | return ( 13 |

14 | {children} 15 |

16 | ) 17 | } 18 | -------------------------------------------------------------------------------- /src/components/section/index.ts: -------------------------------------------------------------------------------- 1 | export { Container } from './Container' 2 | export { Content } from './Content' 3 | export { Image } from './Image' 4 | export { Title } from './Title' 5 | export { Info } from './Info' 6 | export { ContainerContent } from './ContainerContent' 7 | -------------------------------------------------------------------------------- /src/components/section/styles/Content.module.css: -------------------------------------------------------------------------------- 1 | .contentWrapper { 2 | @apply flex flex-col items-start py-36 px-5 md:p-10 w-full lg:px-48 lg:py-40 justify-center relative box-border; 3 | } 4 | 5 | .brand { 6 | @apply bg-brand text-[#000]; 7 | } 8 | 9 | .contentWrapper.black { 10 | @apply bg-zinc-50 text-black dark:bg-[#000] dark:text-white; 11 | } 12 | -------------------------------------------------------------------------------- /src/components/section/styles/Image.module.css: -------------------------------------------------------------------------------- 1 | .image { 2 | @apply flex-grow object-cover object-top md:w-[330px] xl:w-1/3; 3 | } 4 | -------------------------------------------------------------------------------- /src/components/section/styles/Title.module.css: -------------------------------------------------------------------------------- 1 | .title { 2 | @apply text-4xl md:text-6xl font-semibold -translate-y-36 opacity-0 transition-all duration-1000; 3 | } 4 | 5 | .show { 6 | @apply translate-y-0 opacity-100; 7 | } 8 | -------------------------------------------------------------------------------- /src/contants/animationsVariants.ts: -------------------------------------------------------------------------------- 1 | import type { Variants } from 'framer-motion' 2 | export const headerMenuList: Variants = { 3 | open: { 4 | clipPath: 'inset(0% 0% 0% 0% round 10px)', 5 | transition: { 6 | type: 'spring', 7 | bounce: 0, 8 | duration: 0.7, 9 | delayChildren: 0.3, 10 | staggerChildren: 0.05 11 | } 12 | }, 13 | closed: { 14 | clipPath: 'inset(10% 50% 90% 50% round 10px)', 15 | transition: { 16 | type: 'spring', 17 | bounce: 0, 18 | duration: 0.3 19 | } 20 | } 21 | } 22 | 23 | export const headerMenuItem: Variants = { 24 | open: { 25 | opacity: 1, 26 | y: 0, 27 | transition: { 28 | type: 'spring', 29 | stiffness: 300, 30 | damping: 24 31 | } 32 | }, 33 | closed: { 34 | opacity: 0, 35 | y: 20, 36 | transition: { duration: 0.2 } 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /src/contants/seo.ts: -------------------------------------------------------------------------------- 1 | export const seo = { 2 | title: 'Devs Norte', 3 | description: 4 | // eslint-disable-next-line max-len 5 | 'Explore o universo da tecnologia conosco! Faça parte da maior comunidade de desenvolvedores do Norte do Brasil. Conecte-se, aprenda e colabore com profissionais apaixonados por inovação e desenvolvimento de software.', 6 | keywords: [ 7 | 'Desenvolvimento de Software', 8 | 'Programação', 9 | 'Comunidade de Desenvolvedores', 10 | 'Belém', 11 | 'Tecnologia', 12 | 'Código Fonte', 13 | 'Meetups de Desenvolvedores', 14 | 'Eventos Tech', 15 | 'Networking Profissional', 16 | 'Inovação Tecnológica', 17 | 'Startups', 18 | 'Empreendedorismo Digital', 19 | 'Web Development', 20 | 'Mobile Development', 21 | 'Inteligência Artificial', 22 | 'Internet das Coisas (IoT)', 23 | 'Cloud Computing', 24 | 'Linguagens de Programação', 25 | 'Ferramentas de Desenvolvimento', 26 | 'Educação em Tecnologia' 27 | ], 28 | url: 'www.devsnorte.com.br', 29 | urlImage: 'https://devsnorte.netlify.app/_ipx/w_828,q_75/%2Fimages%2Fnetworking.png?url=%2Fimages%2Fnetworking.png' 30 | } 31 | 32 | export const metadata = { 33 | title: seo.title, 34 | description: seo.description, 35 | keywords: seo.keywords, 36 | openGraph: { 37 | title: seo.title, 38 | url: seo.url, 39 | description: seo.description, 40 | type: 'website', 41 | images: [ 42 | { 43 | url: seo.urlImage, 44 | type: 'image/jpg', 45 | width: 1200, 46 | height: 630, 47 | alt: seo.title 48 | } 49 | ] 50 | }, 51 | twitter: { 52 | card: 'summary_large_image', 53 | title: seo.title, 54 | description: seo.description, 55 | images: [ 56 | { 57 | url: seo.urlImage, 58 | type: 'image/jpg', 59 | width: 1200, 60 | height: 630, 61 | alt: 'EMM' 62 | } 63 | ] 64 | } 65 | } 66 | -------------------------------------------------------------------------------- /src/contexts/ThemeContext.tsx: -------------------------------------------------------------------------------- 1 | import { ThemeProviderProps } from '@/types/contexts/themeContextTypes' 2 | import { Theme, ThemeContextType } from '@/types/hooks/useThemeTypes' 3 | import React, { createContext, useState, useEffect } from 'react' 4 | 5 | const defaultContextValue: ThemeContextType = { 6 | theme: 'light', 7 | toggleTheme: () => {} 8 | } 9 | 10 | export const ThemeContext = createContext(defaultContextValue) 11 | 12 | export function ThemeProvider({ children }: ThemeProviderProps) { 13 | const [theme, setTheme] = useState('light') 14 | 15 | useEffect(() => { 16 | const root = document.documentElement 17 | if (theme === 'dark') { 18 | root.classList.add('dark') 19 | root.classList.remove('light') 20 | } else { 21 | root.classList.add('light') 22 | root.classList.remove('dark') 23 | } 24 | }, [theme]) 25 | 26 | useEffect(() => { 27 | const storedTheme = localStorage.getItem('theme') as Theme 28 | if (storedTheme) { 29 | setTheme(storedTheme) 30 | } 31 | }, []) 32 | 33 | const toggleTheme = () => { 34 | const newTheme = theme === 'light' ? 'dark' : 'light' 35 | localStorage.setItem('theme', newTheme) 36 | setTheme(newTheme) 37 | } 38 | 39 | return {children} 40 | } 41 | -------------------------------------------------------------------------------- /src/data/mock/events.ts: -------------------------------------------------------------------------------- 1 | import { Event } from '@/types/components/eventsTypes' 2 | export const mockEvents: Event[] = [ 3 | { 4 | name: '#15 Meetup Devs Norte', 5 | location: { 6 | address: 'Rua Municipalidade', 7 | address_alt: 'Auditório Estácio do Pará, 2º Andar, Bloco D', 8 | city: 'Belém', 9 | address_num: '839', 10 | name: 'Estácio Pará - FAP', 11 | lon: -48.4919638, 12 | state: 'PA', 13 | neighborhood: 'Reduto', 14 | zip_code: '66050-350', 15 | lat: -1.4411707 16 | }, 17 | images: { 18 | original: 'https://images.sympla.com.br/64e39c20a76fa.png', 19 | xs: 'https://images.sympla.com.br/64e39c20a76fa-xs.png', 20 | lg: 'https://images.sympla.com.br/64e39c20a76fa-lg.png' 21 | }, 22 | start_date_formats: { 23 | pt: 'Sab, 26 Ago - 2023 · 08:30', 24 | en: 'Sat, 26 Aug - 2023 · 08:30', 25 | es: 'Sab, 26 Ago - 2023 · 08:30' 26 | }, 27 | end_date_formats: { 28 | pt: 'Sab, 26 Ago - 2023 · 12:00', 29 | en: 'Sat, 26 Aug - 2023 · 12:00', 30 | es: 'Sab, 26 Ago - 2023 · 12:00' 31 | }, 32 | url: 'https://www.sympla.com.br/evento/15-meetup-devs-norte/2128950' 33 | }, 34 | { 35 | images: { 36 | original: 'https://images.sympla.com.br/6474fa5055ffc.png', 37 | xs: 'https://images.sympla.com.br/6474fa5055ffc-xs.png', 38 | lg: 'https://images.sympla.com.br/6474fa5055ffc-lg.png' 39 | }, 40 | start_date_formats: { 41 | pt: 'Sab, 03 Jun - 2023 · 09:00', 42 | en: 'Sat, 03 Jun - 2023 · 09:00', 43 | es: 'Sab, 03 Jun - 2023 · 09:00' 44 | }, 45 | end_date_formats: { 46 | pt: 'Sab, 03 Jun - 2023 · 12:00', 47 | en: 'Sat, 03 Jun - 2023 · 12:00', 48 | es: 'Sab, 03 Jun - 2023 · 12:00' 49 | }, 50 | name: '#12 Meetup Devs Norte | Castanhal', 51 | location: { 52 | address: 'Rodovia BR', 53 | address_alt: '', 54 | city: 'Castanhal', 55 | address_num: '0', 56 | name: 'Estácio Castanhal | Apeú', 57 | lon: -47.9366629, 58 | state: 'PA', 59 | neighborhood: 'Apeú', 60 | zip_code: '68740-420', 61 | lat: -1.305888 62 | }, 63 | url: 'https://www.sympla.com.br/evento/12-meetup-devs-norte-castanhal/2012441' 64 | } 65 | // adicione outros eventos mockados aqui 66 | ] 67 | -------------------------------------------------------------------------------- /src/data/mock/gallery.ts: -------------------------------------------------------------------------------- 1 | import { ImageArray } from '@/types/components/galleryTypes' 2 | 3 | // Crie um array de imagens como dados de exemplo 4 | export const exampleImages: ImageArray = [ 5 | '/images/eventos.png', 6 | '/images/networking.png', 7 | '/images/palestras.png', 8 | '/images/sorteios.png', 9 | '/images/eventos.png', 10 | '/images/networking.png', 11 | '/images/palestras.png', 12 | '/images/sorteios.png', 13 | '/images/eventos.png', 14 | '/images/networking.png', 15 | '/images/palestras.png', 16 | '/images/sorteios.png' 17 | ] 18 | -------------------------------------------------------------------------------- /src/hooks/useBreakpoints.tsx: -------------------------------------------------------------------------------- 1 | import { useEffect, useState } from 'react' 2 | 3 | export const useBreakpoints = () => { 4 | const [windowSize, setWindowSize] = useState({ 5 | height: 0, 6 | width: 0 7 | }) 8 | 9 | useEffect(() => { 10 | if (typeof window !== 'undefined') { 11 | setWindowSize({ 12 | height: window?.innerHeight || 0, 13 | width: window?.innerWidth || 0 14 | }) 15 | } 16 | }, []) 17 | 18 | const handleResize = () => { 19 | setWindowSize({ 20 | height: window?.innerHeight || 0, 21 | width: window?.innerWidth || 0 22 | }) 23 | } 24 | 25 | useEffect(() => { 26 | window?.addEventListener('resize', handleResize) 27 | handleResize() 28 | 29 | return () => window?.removeEventListener('resize', handleResize) 30 | }, [windowSize.width]) 31 | 32 | return { 33 | isCustomBreakpoint: (customWidth: number) => customWidth <= windowSize.width 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /src/hooks/useEventFetcher.tsx: -------------------------------------------------------------------------------- 1 | import { Event } from '@/types/components/eventsTypes' 2 | import { useEffect, useState } from 'react' 3 | 4 | export const useEventFetcher = (initialEventType: 'future' | 'past' = 'future') => { 5 | const [events, setEvents] = useState([]) 6 | const [eventType, setEventType] = useState(initialEventType) 7 | 8 | useEffect(() => { 9 | const fetchData = async (type: string) => { 10 | try { 11 | const response = await fetch('https://www.sympla.com.br/api/v1/search', { 12 | method: 'POST', 13 | headers: { 14 | 'Content-Type': 'application/json' 15 | }, 16 | body: JSON.stringify({ 17 | service: type === 'future' ? '/v4/search' : '/v4/events/past', 18 | params: { 19 | only: 'name,images,location,start_date_formats,end_date_formats,url', 20 | organizer_id: [3125215, 5478152], 21 | sort: 'date', 22 | order_by: 'desc', 23 | limit: '6', 24 | page: 1 25 | }, 26 | ignoreLocation: true 27 | }) 28 | }) 29 | 30 | if (!response.ok) { 31 | throw new Error('Erro ao buscar eventos') 32 | } 33 | 34 | const data = await response.json() 35 | setEvents(data.data) 36 | } catch (error) { 37 | console.error('Erro ao buscar eventos:', error) 38 | } 39 | } 40 | 41 | fetchData(eventType) 42 | }, [eventType]) 43 | 44 | const toggleEventType = () => { 45 | setEventType((prevType) => (prevType === 'future' ? 'past' : 'future')) 46 | } 47 | 48 | return { events, eventType, toggleEventType } 49 | } 50 | -------------------------------------------------------------------------------- /src/hooks/useEvents.ts: -------------------------------------------------------------------------------- 1 | import { Event } from '@/types/components/eventsTypes' 2 | 3 | export type EventType = 'future' | 'past' 4 | 5 | export const useEvents = () => { 6 | async function getEvents(type: EventType): Promise { 7 | const { data } = await fetch('https://www.sympla.com.br/api/v1/search', { 8 | method: 'POST', 9 | headers: { 10 | 'Content-Type': 'application/json' 11 | }, 12 | body: JSON.stringify({ 13 | service: type === 'future' ? '/v4/search' : '/v4/events/past', 14 | params: { 15 | only: 'name,images,location,start_date_formats,end_date_formats,url', 16 | organizer_id: [3125215, 5478152], 17 | sort: 'date', 18 | order_by: 'desc', 19 | limit: '6', 20 | page: 1 21 | }, 22 | ignoreLocation: true 23 | }) 24 | }).then((response) => response.json()) 25 | 26 | return data 27 | } 28 | 29 | return getEvents 30 | } 31 | -------------------------------------------------------------------------------- /src/hooks/useLandingPageInfos.tsx: -------------------------------------------------------------------------------- 1 | import { EventSection } from '@/components/events/EventSection' 2 | import { useTranslation } from 'next-i18next' 3 | import Gallery from '@/components/gallery/Gallery' 4 | import { exampleImages } from '@/data/mock/gallery' 5 | import Link from 'next/link' 6 | import Image from 'next/image' 7 | 8 | export const useLandingPageInfos = () => { 9 | const { t } = useTranslation() 10 | const infos = [ 11 | { 12 | image: { 13 | url: '/images/networking.png', 14 | alt: t('networking') 15 | }, 16 | title: t('Networking'), 17 | info:

{t('networkingSubtitle')}

18 | }, 19 | 20 | { 21 | image: { 22 | url: '/images/sorteios.png', 23 | alt: 'Imagem de Palestra' 24 | }, 25 | title: t('giveaways'), 26 | info:

{t('giveawaysSubtitle')}

27 | }, 28 | { 29 | image: { 30 | url: '/images/palestras.png', 31 | alt: 'Imagem de Palestra' 32 | }, 33 | title: t('lecture'), 34 | info:

{t('lectureSubtitle')}

35 | }, 36 | { 37 | image: { 38 | url: '/images/eventos.png', 39 | alt: 'Eventos Sympla' 40 | }, 41 | title: t('events'), 42 | info: 43 | }, 44 | { 45 | image: { 46 | url: '/images/palestras.png', 47 | alt: 'Imagem de Parcerias' 48 | }, 49 | title: t('partnerships'), 50 | info: ( 51 |
    52 |
  • 53 | {/* Jetbrains:  */} 54 | 55 | Jetbrains 56 | 57 |
  • 58 |
  • 59 | {/* Faculdade Vincit:  */} 60 | 61 | Faculdade Vincit 62 | 63 |
  • 64 |
  • 65 | {/* Fanhero:  */} 66 | 67 | Fanhero 68 | 69 |
  • 70 |
  • 71 | {/* Amazonia Online:  */} 72 | 73 | Amazonia Oline 74 | 75 |
  • 76 |
  • 77 | {/* Iidopterlabs:  */} 78 | 79 | Iidopterlabs 80 | 81 |
  • 82 |
83 | ) 84 | }, 85 | { 86 | title: t('gallery'), 87 | customSection: 88 | } 89 | ] 90 | return infos 91 | } 92 | -------------------------------------------------------------------------------- /src/hooks/useTheme.tsx: -------------------------------------------------------------------------------- 1 | import { ThemeContext } from '@/contexts/ThemeContext' 2 | import { ThemeContextType } from '@/types/hooks/useThemeTypes' 3 | import { useContext } from 'react' 4 | 5 | export const useTheme = (): ThemeContextType => { 6 | const context = useContext(ThemeContext) 7 | if (context === undefined) { 8 | throw new Error('useTheme must be used within a ThemeProvider') 9 | } 10 | return context 11 | } 12 | -------------------------------------------------------------------------------- /src/pages/_app.tsx: -------------------------------------------------------------------------------- 1 | import { appWithTranslation } from 'next-i18next' 2 | import { ThemeProvider } from '@/contexts/ThemeContext' 3 | import { AppProps } from 'next/app' 4 | import { Poppins } from 'next/font/google' 5 | import './globals.css' 6 | 7 | const poppins = Poppins({ 8 | subsets: ['latin'], 9 | weight: ['100', '300', '400', '700', '600'], 10 | variable: '--font-poppins' 11 | }) 12 | 13 | function MyApp({ Component, pageProps }: AppProps) { 14 | return ( 15 | 16 |
17 | {/* eslint-disable-next-line react/jsx-props-no-spreading */} 18 | 19 |
20 |
21 | ) 22 | } 23 | 24 | export default appWithTranslation(MyApp) 25 | -------------------------------------------------------------------------------- /src/pages/_document.tsx: -------------------------------------------------------------------------------- 1 | import { metadata } from '@/contants/seo' 2 | import { Html, Main, Head, NextScript } from 'next/document' 3 | 4 | export default function Document() { 5 | return ( 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | {/* Open Graph */} 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | {/* Twitter */} 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 |
34 | 35 | 36 |