├── .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 | [](#contributors-)
4 |
5 |
6 | 
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 |
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 |
--------------------------------------------------------------------------------
/public/icons/devsnorte-hero-light.svg:
--------------------------------------------------------------------------------
1 |
19 |
--------------------------------------------------------------------------------
/public/icons/devsnorte-hero.svg:
--------------------------------------------------------------------------------
1 |
19 |
--------------------------------------------------------------------------------
/public/icons/dot.svg:
--------------------------------------------------------------------------------
1 |
2 |
--------------------------------------------------------------------------------
/public/icons/favicon.svg:
--------------------------------------------------------------------------------
1 |
11 |
--------------------------------------------------------------------------------
/public/icons/line-section.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/public/icons/loading.svg:
--------------------------------------------------------------------------------
1 |
2 |
--------------------------------------------------------------------------------
/public/icons/logo-light.svg:
--------------------------------------------------------------------------------
1 |
17 |
--------------------------------------------------------------------------------
/public/icons/logo.svg:
--------------------------------------------------------------------------------
1 |
17 |
--------------------------------------------------------------------------------
/public/icons/menu.svg:
--------------------------------------------------------------------------------
1 |
7 |
--------------------------------------------------------------------------------
/public/icons/rectangle-section.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/public/icons/star.svg:
--------------------------------------------------------------------------------
1 |
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 |
--------------------------------------------------------------------------------
/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 |
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 |
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 |
83 |
84 | ))}
85 |
86 | ))}
87 |
88 |
89 | {isModalOpen ? (
90 |
95 | e.stopPropagation()}
101 | >
102 |
107 | ×
108 |
109 |
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 |
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 |
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 |
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 |
56 |
57 |
58 | -
59 | {/* Faculdade Vincit: */}
60 |
61 |
62 |
63 |
64 | -
65 | {/* Fanhero: */}
66 |
67 |
68 |
69 |
70 | -
71 | {/* Amazonia Online: */}
72 |
73 |
74 |
75 |
76 | -
77 | {/* Iidopterlabs: */}
78 |
79 |
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 |
37 |
38 | )
39 | }
40 |
--------------------------------------------------------------------------------
/src/pages/globals.css:
--------------------------------------------------------------------------------
1 | @tailwind base;
2 | @tailwind components;
3 | @tailwind utilities;
4 | * {
5 | -webkit-font-smoothing: antialiased;
6 | }
7 |
8 | body {
9 | @apply font-poppins;
10 | }
11 |
12 | @layer utilities {
13 | .text-balance {
14 | text-wrap: balance;
15 | }
16 | }
17 |
18 | @media (max-width: 700px) {
19 | .modal-content {
20 | width: 80%;
21 | }
22 | }
23 |
24 | /* Write a comment */
25 | .modal-content img,
26 | .modal-content .image-class {
27 | max-width: 60%;
28 | max-height: 100%;
29 | object-fit: contain;
30 | display: block;
31 | margin: 0 auto;
32 | }
33 |
34 | /* Add Animation */
35 | @keyframes animatetop {
36 | from {
37 | top: -300px;
38 | opacity: 0;
39 | }
40 | to {
41 | top: 0;
42 | opacity: 1;
43 | }
44 | }
45 |
46 | .close {
47 | color: #aaa;
48 | float: right;
49 | font-size: 28px;
50 | font-weight: bold;
51 | }
52 |
53 | .close:hover,
54 | .close:focus {
55 | color: black;
56 | text-decoration: none;
57 | cursor: pointer;
58 | }
59 |
--------------------------------------------------------------------------------
/src/pages/index.tsx:
--------------------------------------------------------------------------------
1 | import { Header } from '@/components/header'
2 | import { Hero } from '@/components/hero'
3 | import { Newsletter } from '@/components/newsletter'
4 | import { SectionPrincipal } from '@/components/section/Section'
5 | import { seo } from '@/contants/seo'
6 | import { NextPageContext } from 'next'
7 | import { serverSideTranslations } from 'next-i18next/serverSideTranslations'
8 | import Head from 'next/head'
9 |
10 | function Home() {
11 | return (
12 |
13 |
14 |
{seo.title}
15 |
16 |
17 |
18 |
19 |
20 |
21 | )
22 | }
23 |
24 | export default Home
25 |
26 | export const getStaticProps = async (context: NextPageContext) => {
27 | const { locale } = context
28 | return {
29 | props: {
30 | ...(await serverSideTranslations(locale as string, ['common']))
31 | }
32 | }
33 | }
34 |
--------------------------------------------------------------------------------
/src/types/components/dropdownTypes.ts:
--------------------------------------------------------------------------------
1 | import { ReactNode } from 'react'
2 |
3 | export interface DropDownProps {
4 | placeholder: ReactNode
5 | data: { label: string; value: unknown }[]
6 | onSelect: (_value: unknown) => void
7 | }
8 |
--------------------------------------------------------------------------------
/src/types/components/eventsTypes.ts:
--------------------------------------------------------------------------------
1 | export interface EventLocation {
2 | address: string
3 | address_alt: string
4 | city: string
5 | address_num: string
6 | name: string
7 | lon: number
8 | state: string
9 | neighborhood: string
10 | zip_code: string
11 | lat: number
12 | }
13 |
14 | export interface Event {
15 | name: string
16 | location: EventLocation
17 | images: {
18 | original: string
19 | xs: string
20 | lg: string
21 | }
22 | start_date_formats: {
23 | pt: string
24 | en: string
25 | es: string
26 | }
27 | end_date_formats: {
28 | pt: string
29 | en: string
30 | es: string
31 | }
32 | url: string
33 | }
34 |
35 | export interface EventCardProps {
36 | event: Event
37 | }
38 |
39 | export interface EventListProps {
40 | events: Event[]
41 | }
42 |
--------------------------------------------------------------------------------
/src/types/components/galleryTypes.ts:
--------------------------------------------------------------------------------
1 | export type ImageArray = string[]
2 |
3 | export interface GalleryProps {
4 | images: ImageArray
5 | }
6 |
--------------------------------------------------------------------------------
/src/types/components/sectionTypes.ts:
--------------------------------------------------------------------------------
1 | import type { ImageProps } from 'next/image'
2 |
3 | export interface TitleProps {
4 | children: React.ReactNode
5 | }
6 |
7 | export interface TextProps {
8 | children: React.ReactNode
9 | }
10 |
11 | export interface SectionContentProps {
12 | variant?: 'brand' | 'black'
13 | children: React.ReactNode
14 | }
15 |
16 | export interface SectionImageProps extends ImageProps {}
17 |
18 | export interface SectionContainerProps {
19 | children: React.ReactNode
20 | id?: string
21 | }
22 |
23 | export interface SectionContainerContentProps {
24 | children: React.ReactNode
25 | }
26 |
--------------------------------------------------------------------------------
/src/types/contexts/themeContextTypes.ts:
--------------------------------------------------------------------------------
1 | import { ReactNode } from 'react'
2 |
3 | export interface ThemeProviderProps {
4 | children: ReactNode
5 | }
6 |
--------------------------------------------------------------------------------
/src/types/hooks/useThemeTypes.ts:
--------------------------------------------------------------------------------
1 | export type Theme = 'light' | 'dark'
2 |
3 | export interface ThemeContextType {
4 | theme: Theme
5 | toggleTheme: () => void
6 | }
7 |
--------------------------------------------------------------------------------
/tailwind.config.ts:
--------------------------------------------------------------------------------
1 | import type { Config } from 'tailwindcss'
2 |
3 | const config: Config = {
4 | content: ['./src/pages/**/*.{js,ts,jsx,tsx,mdx}', './src/components/**/*.{js,ts,jsx,tsx,mdx}', './src/app/**/*.{js,ts,jsx,tsx,mdx}'],
5 | darkMode: 'class',
6 | theme: {
7 | extend: {
8 | screens: {
9 | slg: '1200px'
10 | },
11 | fontFamily: {
12 | poppins: 'var(--font-poppins)'
13 | },
14 | colors: {
15 | brand: '#5ED29E'
16 | },
17 | maxWidth: {}
18 | }
19 | },
20 | plugins: []
21 | }
22 | export default config
23 |
--------------------------------------------------------------------------------
/tsconfig.json:
--------------------------------------------------------------------------------
1 | {
2 | "compilerOptions": {
3 | "lib": [
4 | "dom",
5 | "dom.iterable",
6 | "esnext"
7 | ],
8 | "allowJs": true,
9 | "skipLibCheck": true,
10 | "strict": true,
11 | "noEmit": true,
12 | "esModuleInterop": true,
13 | "module": "esnext",
14 | "moduleResolution": "bundler",
15 | "resolveJsonModule": true,
16 | "isolatedModules": true,
17 | "jsx": "preserve",
18 | "incremental": true,
19 | "plugins": [
20 | {
21 | "name": "next"
22 | }
23 | ],
24 | "paths": {
25 | "@/*": [
26 | "./src/*"
27 | ]
28 | }
29 | },
30 | "include": [
31 | "next-env.d.ts",
32 | "**/*.ts",
33 | "**/*.tsx",
34 | ".next/types/**/*.ts",
35 | "**/**/*.d.ts"
36 | ],
37 | "exclude": [
38 | "node_modules"
39 | ]
40 | }
--------------------------------------------------------------------------------