├── .husky ├── .gitignore ├── pre-commit └── commit-msg ├── .prettierignore ├── cypress.json ├── commitlint.config.js ├── public ├── favicon.ico ├── img │ ├── home-header.png │ └── bellshade-logo.png └── vercel.svg ├── .eslintrc.json ├── postcss.config.js ├── pages ├── _app.js ├── api │ └── hello.js ├── index.js └── _document.js ├── cypress ├── fixtures │ └── example.json ├── integration │ ├── 2-advanced-examples │ │ ├── window.spec.js │ │ ├── waiting.spec.js │ │ ├── location.spec.js │ │ ├── aliasing.spec.js │ │ ├── navigation.spec.js │ │ ├── viewport.spec.js │ │ ├── local_storage.spec.js │ │ ├── cookies.spec.js │ │ ├── files.spec.js │ │ ├── connectors.spec.js │ │ ├── misc.spec.js │ │ ├── utilities.spec.js │ │ ├── querying.spec.js │ │ ├── traversal.spec.js │ │ ├── assertions.spec.js │ │ ├── cypress_api.spec.js │ │ ├── spies_stubs_clocks.spec.js │ │ ├── network_requests.spec.js │ │ └── actions.spec.js │ └── 1-getting-started │ │ └── todo.spec.js ├── support │ ├── index.js │ └── commands.js └── plugins │ └── index.js ├── next.config.js ├── jsconfig.json ├── components └── pages │ └── home │ ├── Navbar.stories.js │ ├── HomeHeader.stories.js │ ├── OurTeam.stories.js │ ├── HomeHeader.js │ ├── OurTeam.js │ └── Navbar.js ├── tailwind.config.js ├── .github ├── ISSUE_TEMPLATE │ ├── bug-report.md │ ├── epic.md │ └── feature-request.md └── pull_request_template.md ├── .storybook ├── preview.js └── main.js ├── .gitignore ├── .mergify.yml ├── README nextjs.md ├── package.json ├── styles ├── Home.module.css └── globals.css ├── utils └── lib │ └── deferNextScript.js └── README.md /.husky/.gitignore: -------------------------------------------------------------------------------- 1 | _ 2 | -------------------------------------------------------------------------------- /.prettierignore: -------------------------------------------------------------------------------- 1 | .next 2 | -------------------------------------------------------------------------------- /cypress.json: -------------------------------------------------------------------------------- 1 | { 2 | "baseUrl": "http://localhost:3000" 3 | } 4 | -------------------------------------------------------------------------------- /.husky/pre-commit: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | . "$(dirname "$0")/_/husky.sh" 3 | 4 | npx lint-staged 5 | -------------------------------------------------------------------------------- /commitlint.config.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | extends: ["@commitlint/config-conventional"], 3 | }; 4 | -------------------------------------------------------------------------------- /public/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bellshade/bellshade-website-v2/HEAD/public/favicon.ico -------------------------------------------------------------------------------- /.husky/commit-msg: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | . "$(dirname "$0")/_/husky.sh" 3 | 4 | npx --no -- commitlint --edit "" 5 | -------------------------------------------------------------------------------- /.eslintrc.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": ["next/core-web-vitals", "prettier"], 3 | "plugins": ["cypress"] 4 | } 5 | -------------------------------------------------------------------------------- /public/img/home-header.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bellshade/bellshade-website-v2/HEAD/public/img/home-header.png -------------------------------------------------------------------------------- /postcss.config.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | plugins: { 3 | tailwindcss: {}, 4 | autoprefixer: {}, 5 | }, 6 | }; 7 | -------------------------------------------------------------------------------- /public/img/bellshade-logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bellshade/bellshade-website-v2/HEAD/public/img/bellshade-logo.png -------------------------------------------------------------------------------- /pages/_app.js: -------------------------------------------------------------------------------- 1 | import "@/styles/globals.css"; 2 | 3 | function MyApp({ Component, pageProps }) { 4 | return ; 5 | } 6 | 7 | export default MyApp; 8 | -------------------------------------------------------------------------------- /cypress/fixtures/example.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "Using fixtures to represent data", 3 | "email": "hello@cypress.io", 4 | "body": "Fixtures are a great way to mock data for responses to routes" 5 | } 6 | -------------------------------------------------------------------------------- /pages/api/hello.js: -------------------------------------------------------------------------------- 1 | // Next.js API route support: https://nextjs.org/docs/api-routes/introduction 2 | 3 | export default function handler(req, res) { 4 | res.status(200).json({ name: "John Doe" }); 5 | } 6 | -------------------------------------------------------------------------------- /next.config.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | reactStrictMode: true, 3 | swcMinify: true, 4 | images: { 5 | formats: ["image/avif", "image/webp"], 6 | domains: ["avatars.githubusercontent.com"], 7 | }, 8 | }; 9 | -------------------------------------------------------------------------------- /jsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "baseUrl": ".", 4 | "paths": { 5 | "@/lib/*": ["utils/lib/*"], 6 | "@/components/*": ["components/*"], 7 | "@/utils/*": ["utils/*"], 8 | "@/styles/*": ["styles/*"], 9 | } 10 | } 11 | } 12 | -------------------------------------------------------------------------------- /components/pages/home/Navbar.stories.js: -------------------------------------------------------------------------------- 1 | import React from "react"; 2 | import Navbar from "./Navbar"; 3 | 4 | const defExport = { 5 | title: "Pages/Home/Navbar", 6 | component: Navbar, 7 | }; 8 | 9 | export default defExport; 10 | const Template = (args) => ; 11 | export const navbar = Template.bind(); 12 | -------------------------------------------------------------------------------- /components/pages/home/HomeHeader.stories.js: -------------------------------------------------------------------------------- 1 | import React from "react"; 2 | import HomeHeader from "./HomeHeader"; 3 | 4 | const defExport = { 5 | title: "Pages/Home/Header", 6 | component: HomeHeader, 7 | }; 8 | 9 | export default defExport; 10 | const Template = (args) => ; 11 | export const Header = Template.bind(); 12 | -------------------------------------------------------------------------------- /tailwind.config.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | content: [ 3 | "./pages/**/*.{js,ts,jsx,tsx}", 4 | "./components/**/*.{js,ts,jsx,tsx}", 5 | "./stories/**/*.{js,ts,jsx,tsx}", 6 | ], 7 | theme: { 8 | extend: { 9 | colors: { 10 | main: "#637FE3", 11 | }, 12 | }, 13 | }, 14 | plugins: [], 15 | }; 16 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/bug-report.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: Lapor Kesalahan 3 | about: Sesuatu yang tidak berjalan semestinya. 4 | title: "" 5 | labels: bug 6 | --- 7 | 8 | ## Deskripsi 9 | 10 | 11 | 12 | ## Perilaku yang diharapkan 13 | 14 | 15 | 16 | ## Informasi tambahan 17 | 18 | 19 | -------------------------------------------------------------------------------- /.storybook/preview.js: -------------------------------------------------------------------------------- 1 | import React from "react"; 2 | import "../styles/globals.css"; 3 | import * as NextImage from "next/image"; 4 | 5 | const OriginalNextImage = NextImage.default; 6 | 7 | Object.defineProperty(NextImage, "default", { 8 | configurable: true, 9 | value: (props) => , 10 | }); 11 | 12 | export const parameters = { 13 | controls: { expanded: true }, 14 | }; 15 | export const decorators = [(storyFn) =>
{storyFn()}
]; 16 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/epic.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: Epic 3 | about: Kumpulan isu yang berisikan berbagai isu kecil lain. 4 | title: "" 5 | labels: epic 6 | --- 7 | 8 | ## Gambaran 9 | 10 | 11 | 12 | ## Daftar Tugas 13 | 14 | 16 | 17 | - [ ] (tugas 1) 18 | - [ ] (tugas 2) 19 | - [ ] (tugas 3) 20 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # See https://help.github.com/articles/ignoring-files/ for more about ignoring files. 2 | 3 | # dependencies 4 | /node_modules 5 | /.pnp 6 | .pnp.js 7 | 8 | # testing 9 | /coverage 10 | .eslintcache 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 | .env.development.local 31 | .env.test.local 32 | .env.production.local 33 | 34 | # vercel 35 | .vercel 36 | -------------------------------------------------------------------------------- /.storybook/main.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | stories: [ 3 | "../components/**/*.stories.@(js|jsx|ts|tsx)", 4 | "../components/**/**/*.stories.@(js|jsx|ts|tsx)", 5 | ], 6 | addons: [ 7 | "@storybook/addon-actions", 8 | "@storybook/addon-docs", 9 | "@storybook/addon-controls", 10 | "@storybook/addon-viewport", 11 | { 12 | name: "@storybook/addon-postcss", 13 | options: { 14 | postcssLoaderOptions: { 15 | implementation: require("postcss"), 16 | }, 17 | }, 18 | }, 19 | ], 20 | staticDirs: ["../public"], 21 | }; 22 | -------------------------------------------------------------------------------- /.github/pull_request_template.md: -------------------------------------------------------------------------------- 1 | Closes 2 | 3 | ## Deskripsi 4 | 5 | 6 | 7 | ## Environment 8 | 9 | 10 | 11 | Saya menggunakan sistem operasi: 12 | 13 | - `os` = `linux / windows / macOS` 14 | 15 | ## Daftar Tugas 16 | 17 | 19 | 20 | - [ ] (tugas 1) 21 | - [ ] (tugas 2) 22 | - [ ] (tugas 3) 23 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/feature-request.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: Permintaan Fitur 3 | about: Usulkan penambahan fitur ke proyek. 4 | title: "" 5 | labels: enhancement 6 | --- 7 | 8 | ## Deskripsi 9 | 10 | 11 | 12 | ## Implementation Model 13 | 14 | 15 | 16 | ## Daftar Tugas 17 | 18 | 19 | 20 | - [ ] (tugas 1) 21 | - [ ] (tugas 2) 22 | - [ ] (tugas 3) 23 | -------------------------------------------------------------------------------- /cypress/integration/2-advanced-examples/window.spec.js: -------------------------------------------------------------------------------- 1 | /// 2 | 3 | context("Window", () => { 4 | beforeEach(() => { 5 | cy.visit("https://example.cypress.io/commands/window"); 6 | }); 7 | 8 | it("cy.window() - get the global window object", () => { 9 | // https://on.cypress.io/window 10 | cy.window().should("have.property", "top"); 11 | }); 12 | 13 | it("cy.document() - get the document object", () => { 14 | // https://on.cypress.io/document 15 | cy.document().should("have.property", "charset").and("eq", "UTF-8"); 16 | }); 17 | 18 | it("cy.title() - get the title", () => { 19 | // https://on.cypress.io/title 20 | cy.title().should("include", "Kitchen Sink"); 21 | }); 22 | }); 23 | -------------------------------------------------------------------------------- /cypress/support/index.js: -------------------------------------------------------------------------------- 1 | // *********************************************************** 2 | // This example support/index.js is processed and 3 | // loaded automatically before your test files. 4 | // 5 | // This is a great place to put global configuration and 6 | // behavior that modifies Cypress. 7 | // 8 | // You can change the location of this file or turn off 9 | // automatically serving support files with the 10 | // 'supportFile' configuration option. 11 | // 12 | // You can read more here: 13 | // https://on.cypress.io/configuration 14 | // *********************************************************** 15 | 16 | // Import commands.js using ES2015 syntax: 17 | import "./commands"; 18 | 19 | // Alternatively you can use CommonJS syntax: 20 | // require('./commands') 21 | -------------------------------------------------------------------------------- /cypress/plugins/index.js: -------------------------------------------------------------------------------- 1 | /// 2 | // *********************************************************** 3 | // This example plugins/index.js can be used to load plugins 4 | // 5 | // You can change the location of this file or turn off loading 6 | // the plugins file with the 'pluginsFile' configuration option. 7 | // 8 | // You can read more here: 9 | // https://on.cypress.io/plugins-guide 10 | // *********************************************************** 11 | 12 | // This function is called when a project is opened or re-opened (e.g. due to 13 | // the project's config changing) 14 | 15 | /** 16 | * @type {Cypress.PluginConfig} 17 | */ 18 | // eslint-disable-next-line no-unused-vars 19 | module.exports = (on, config) => { 20 | // `on` is used to hook into various events Cypress emits 21 | // `config` is the resolved Cypress config 22 | }; 23 | -------------------------------------------------------------------------------- /pages/index.js: -------------------------------------------------------------------------------- 1 | import Head from "next/head"; 2 | import Navbar from "@/components/pages/home/Navbar"; 3 | import HomeHeader from "@/components/pages/home/HomeHeader"; 4 | import OurTeam from "@/components/pages/home/OurTeam"; 5 | 6 | const Home = ({ members }) => { 7 | return ( 8 |
9 | 10 | Bellshade - Learn with Our Community 11 | 12 | 13 | 14 | 15 |
16 | ); 17 | }; 18 | 19 | export default Home; 20 | 21 | export async function getStaticProps() { 22 | const BellshadeAPI = "https://api.bellshade.org/"; 23 | const getContents = (url) => fetch(url).then((res) => res.json()); 24 | 25 | const getPublicMembers = await getContents(BellshadeAPI); 26 | 27 | return { 28 | props: { 29 | members: getPublicMembers, 30 | }, 31 | revalidate: 432000, 32 | }; 33 | } -------------------------------------------------------------------------------- /cypress/support/commands.js: -------------------------------------------------------------------------------- 1 | // *********************************************** 2 | // This example commands.js shows you how to 3 | // create various custom commands and overwrite 4 | // existing commands. 5 | // 6 | // For more comprehensive examples of custom 7 | // commands please read more here: 8 | // https://on.cypress.io/custom-commands 9 | // *********************************************** 10 | // 11 | // 12 | // -- This is a parent command -- 13 | // Cypress.Commands.add('login', (email, password) => { ... }) 14 | // 15 | // 16 | // -- This is a child command -- 17 | // Cypress.Commands.add('drag', { prevSubject: 'element'}, (subject, options) => { ... }) 18 | // 19 | // 20 | // -- This is a dual command -- 21 | // Cypress.Commands.add('dismiss', { prevSubject: 'optional'}, (subject, options) => { ... }) 22 | // 23 | // 24 | // -- This will overwrite an existing command -- 25 | // Cypress.Commands.overwrite('visit', (originalFn, url, options) => { ... }) 26 | -------------------------------------------------------------------------------- /components/pages/home/OurTeam.stories.js: -------------------------------------------------------------------------------- 1 | import React from "react"; 2 | import { MemberCard } from "./OurTeam"; 3 | 4 | const controlTypeText = { 5 | type: "text", 6 | }; 7 | 8 | const defExport = { 9 | title: "Pages/Home/MemberCard", 10 | component: MemberCard, 11 | argTypes: { 12 | login: { 13 | description: "Username github", 14 | defaultValue: "bellshade", 15 | control: controlTypeText, 16 | }, 17 | name: { 18 | description: "Name github", 19 | defaultValue: "Bellshade", 20 | control: controlTypeText, 21 | }, 22 | html_url: { 23 | description: "Link menuju profile github", 24 | defaultValue: "https://github.com/bellshade", 25 | control: controlTypeText, 26 | }, 27 | avatar_url: { 28 | description: "Link avatar dari user github", 29 | defaultValue: 30 | "https://avatars.githubusercontent.com/u/76999048?s=200&v=4", 31 | control: controlTypeText, 32 | }, 33 | }, 34 | }; 35 | 36 | export default defExport; 37 | 38 | export const Example = (args) => ; -------------------------------------------------------------------------------- /pages/_document.js: -------------------------------------------------------------------------------- 1 | import DeferNextScript from "@/lib/deferNextScript"; 2 | import Document, { Html, Head, Main } from "next/document"; 3 | 4 | class MyDocument extends Document { 5 | static async getInitialProps(ctx) { 6 | return await Document.getInitialProps(ctx); 7 | } 8 | 9 | render() { 10 | return ( 11 | 12 | 13 | 14 | 15 | 16 | 21 | 25 | 26 | 27 |
28 | 29 | 30 | 31 | ); 32 | } 33 | } 34 | 35 | export default MyDocument; 36 | -------------------------------------------------------------------------------- /public/vercel.svg: -------------------------------------------------------------------------------- 1 | 3 | 4 | -------------------------------------------------------------------------------- /.mergify.yml: -------------------------------------------------------------------------------- 1 | pull_request_rules: 2 | # membuat requirement dari automerge dengan sistem 3 | # ketika workflow build passed maka akan dicentang 4 | # ketika target pull request ke main maka akan dicentang 5 | # ketika dikasih label 'ready-to-merge' akan dicentang 6 | 7 | # ketika requirement telah terpenuhi maka bot akan bekerja 8 | # dan pull request secara otomatis akan merge 9 | - name: merge ketika check sudah terpenuhi 10 | conditions: 11 | # di comment karena tidak memiliki unit testing github action 12 | # - check-success=build 13 | # jika pull request ke main maka akan dicentang 14 | - base=main 15 | # jika sudah menambahkan label ready to merge maka akan dicentang 16 | - label=ready-to-merge 17 | actions: 18 | # menambahkan komentar jika sudah di merge 19 | comment: 20 | message: terima kasih atas kontribusinya @{{author}}! 21 | # menambahkan label jika sudah di merge 22 | label: 23 | add: 24 | - sudah dirieview! 25 | # metode sistem dari automerge 26 | merge: 27 | method: merge 28 | -------------------------------------------------------------------------------- /cypress/integration/2-advanced-examples/waiting.spec.js: -------------------------------------------------------------------------------- 1 | /// 2 | 3 | context("Waiting", () => { 4 | beforeEach(() => { 5 | cy.visit("https://example.cypress.io/commands/waiting"); 6 | }); 7 | // BE CAREFUL of adding unnecessary wait times. 8 | // https://on.cypress.io/best-practices#Unnecessary-Waiting 9 | 10 | // https://on.cypress.io/wait 11 | it("cy.wait() - wait for a specific amount of time", () => { 12 | cy.get(".wait-input1").type("Wait 1000ms after typing"); 13 | cy.wait(1000); 14 | cy.get(".wait-input2").type("Wait 1000ms after typing"); 15 | cy.wait(1000); 16 | cy.get(".wait-input3").type("Wait 1000ms after typing"); 17 | cy.wait(1000); 18 | }); 19 | 20 | it("cy.wait() - wait for a specific route", () => { 21 | // Listen to GET to comments/1 22 | cy.intercept("GET", "**/comments/*").as("getComment"); 23 | 24 | // we have code that gets a comment when 25 | // the button is clicked in scripts.js 26 | cy.get(".network-btn").click(); 27 | 28 | // wait for GET comments/1 29 | cy.wait("@getComment") 30 | .its("response.statusCode") 31 | .should("be.oneOf", [200, 304]); 32 | }); 33 | }); 34 | -------------------------------------------------------------------------------- /components/pages/home/HomeHeader.js: -------------------------------------------------------------------------------- 1 | import Image from "next/image"; 2 | 3 | const HomeHeader = () => { 4 | return ( 5 |
6 |
10 |
11 |

12 | Funky Study Coding with{" "} 13 | Bellshade 14 |

15 |

16 | Belajar materi tentang coding, quiz, dan juga bisa belajar bareng di 17 | komunitas Web Programming UNPAS 18 |

19 | 25 |
26 |
27 | Home-Header-Image 33 |
34 |
35 |
36 | ); 37 | }; 38 | 39 | export default HomeHeader; 40 | -------------------------------------------------------------------------------- /cypress/integration/2-advanced-examples/location.spec.js: -------------------------------------------------------------------------------- 1 | /// 2 | 3 | context("Location", () => { 4 | beforeEach(() => { 5 | cy.visit("https://example.cypress.io/commands/location"); 6 | }); 7 | 8 | it("cy.hash() - get the current URL hash", () => { 9 | // https://on.cypress.io/hash 10 | cy.hash().should("be.empty"); 11 | }); 12 | 13 | it("cy.location() - get window.location", () => { 14 | // https://on.cypress.io/location 15 | cy.location().should((location) => { 16 | expect(location.hash).to.be.empty; 17 | expect(location.href).to.eq( 18 | "https://example.cypress.io/commands/location" 19 | ); 20 | expect(location.host).to.eq("example.cypress.io"); 21 | expect(location.hostname).to.eq("example.cypress.io"); 22 | expect(location.origin).to.eq("https://example.cypress.io"); 23 | expect(location.pathname).to.eq("/commands/location"); 24 | expect(location.port).to.eq(""); 25 | expect(location.protocol).to.eq("https:"); 26 | expect(location.search).to.be.empty; 27 | }); 28 | }); 29 | 30 | it("cy.url() - get the current URL", () => { 31 | // https://on.cypress.io/url 32 | cy.url().should("eq", "https://example.cypress.io/commands/location"); 33 | }); 34 | }); 35 | -------------------------------------------------------------------------------- /cypress/integration/2-advanced-examples/aliasing.spec.js: -------------------------------------------------------------------------------- 1 | /// 2 | 3 | context("Aliasing", () => { 4 | beforeEach(() => { 5 | cy.visit("https://example.cypress.io/commands/aliasing"); 6 | }); 7 | 8 | it(".as() - alias a DOM element for later use", () => { 9 | // https://on.cypress.io/as 10 | 11 | // Alias a DOM element for use later 12 | // We don't have to traverse to the element 13 | // later in our code, we reference it with @ 14 | 15 | cy.get(".as-table") 16 | .find("tbody>tr") 17 | .first() 18 | .find("td") 19 | .first() 20 | .find("button") 21 | .as("firstBtn"); 22 | 23 | // when we reference the alias, we place an 24 | // @ in front of its name 25 | cy.get("@firstBtn").click(); 26 | 27 | cy.get("@firstBtn") 28 | .should("have.class", "btn-success") 29 | .and("contain", "Changed"); 30 | }); 31 | 32 | it(".as() - alias a route for later use", () => { 33 | // Alias the route to wait for its response 34 | cy.intercept("GET", "**/comments/*").as("getComment"); 35 | 36 | // we have code that gets a comment when 37 | // the button is clicked in scripts.js 38 | cy.get(".network-btn").click(); 39 | 40 | // https://on.cypress.io/wait 41 | cy.wait("@getComment").its("response.statusCode").should("eq", 200); 42 | }); 43 | }); 44 | -------------------------------------------------------------------------------- /README nextjs.md: -------------------------------------------------------------------------------- 1 | This is a [Next.js](https://nextjs.org/) project bootstrapped with [`create-next-app`](https://github.com/vercel/next.js/tree/canary/packages/create-next-app). 2 | 3 | ## Getting Started 4 | 5 | First, run the development server: 6 | 7 | ```bash 8 | npm run dev 9 | # or 10 | yarn dev 11 | ``` 12 | 13 | Open [http://localhost:3000](http://localhost:3000) with your browser to see the result. 14 | 15 | You can start editing the page by modifying `pages/index.js`. The page auto-updates as you edit the file. 16 | 17 | [API routes](https://nextjs.org/docs/api-routes/introduction) can be accessed on [http://localhost:3000/api/hello](http://localhost:3000/api/hello). This endpoint can be edited in `pages/api/hello.js`. 18 | 19 | The `pages/api` directory is mapped to `/api/*`. Files in this directory are treated as [API routes](https://nextjs.org/docs/api-routes/introduction) instead of React pages. 20 | 21 | ## Learn More 22 | 23 | To learn more about Next.js, take a look at the following resources: 24 | 25 | - [Next.js Documentation](https://nextjs.org/docs) - learn about Next.js features and API. 26 | - [Learn Next.js](https://nextjs.org/learn) - an interactive Next.js tutorial. 27 | 28 | You can check out [the Next.js GitHub repository](https://github.com/vercel/next.js/) - your feedback and contributions are welcome! 29 | 30 | ## Deploy on Vercel 31 | 32 | The easiest way to deploy your Next.js app is to use the [Vercel Platform](https://vercel.com/new?utm_medium=default-template&filter=next.js&utm_source=create-next-app&utm_campaign=create-next-app-readme) from the creators of Next.js. 33 | 34 | Check out our [Next.js deployment documentation](https://nextjs.org/docs/deployment) for more details. 35 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "bellshade-v2", 3 | "private": true, 4 | "scripts": { 5 | "dev": "next dev", 6 | "build": "next build", 7 | "build-storybook": "build-storybook", 8 | "start": "next start", 9 | "lint": "next lint", 10 | "prettier": "prettier -w .", 11 | "cypress": "cypress open", 12 | "cypress:headless": "cypress run", 13 | "e2e": "start-server-and-test start http://localhost:3000 cypress", 14 | "e2e:headless": "start-server-and-test start http://localhost:3000 cypress:headless", 15 | "storybook": "start-storybook -p 9009 -c .storybook", 16 | "prepare": "husky install" 17 | }, 18 | "dependencies": { 19 | "next": "12.1.0", 20 | "react": "17.0.2", 21 | "react-dom": "17.0.2" 22 | }, 23 | "devDependencies": { 24 | "@commitlint/cli": "^16.0.2", 25 | "@commitlint/config-conventional": "^16.0.0", 26 | "@iconify/react": "^3.1.4", 27 | "@storybook/addon-actions": "^6.4.13", 28 | "@storybook/addon-controls": "^6.4.13", 29 | "@storybook/addon-docs": "^6.4.13", 30 | "@storybook/addon-postcss": "^2.0.0", 31 | "@storybook/addon-viewport": "^6.4.13", 32 | "@storybook/react": "^6.4.13", 33 | "autoprefixer": "^10.4.1", 34 | "cypress": "^9.2.1", 35 | "eslint": "^8.6.0", 36 | "eslint-config-next": "12.0.7", 37 | "eslint-config-prettier": "^8.3.0", 38 | "eslint-plugin-cypress": "^2.12.1", 39 | "husky": "^7.0.4", 40 | "lint-staged": "^12.1.7", 41 | "postcss": "^8.4.5", 42 | "prettier": "^2.5.1", 43 | "start-server-and-test": "^1.14.0", 44 | "tailwindcss": "^3.0.10" 45 | }, 46 | "lint-staged": { 47 | "*.js": "eslint --cache --fix", 48 | "*.{js,css,md}": "prettier --write" 49 | } 50 | } 51 | -------------------------------------------------------------------------------- /cypress/integration/2-advanced-examples/navigation.spec.js: -------------------------------------------------------------------------------- 1 | /// 2 | 3 | context("Navigation", () => { 4 | beforeEach(() => { 5 | cy.visit("https://example.cypress.io"); 6 | cy.get(".navbar-nav").contains("Commands").click(); 7 | cy.get(".dropdown-menu").contains("Navigation").click(); 8 | }); 9 | 10 | it("cy.go() - go back or forward in the browser's history", () => { 11 | // https://on.cypress.io/go 12 | 13 | cy.location("pathname").should("include", "navigation"); 14 | 15 | cy.go("back"); 16 | cy.location("pathname").should("not.include", "navigation"); 17 | 18 | cy.go("forward"); 19 | cy.location("pathname").should("include", "navigation"); 20 | 21 | // clicking back 22 | cy.go(-1); 23 | cy.location("pathname").should("not.include", "navigation"); 24 | 25 | // clicking forward 26 | cy.go(1); 27 | cy.location("pathname").should("include", "navigation"); 28 | }); 29 | 30 | it("cy.reload() - reload the page", () => { 31 | // https://on.cypress.io/reload 32 | cy.reload(); 33 | 34 | // reload the page without using the cache 35 | cy.reload(true); 36 | }); 37 | 38 | it("cy.visit() - visit a remote url", () => { 39 | // https://on.cypress.io/visit 40 | 41 | // Visit any sub-domain of your current domain 42 | 43 | // Pass options to the visit 44 | cy.visit("https://example.cypress.io/commands/navigation", { 45 | timeout: 50000, // increase total time for the visit to resolve 46 | onBeforeLoad(contentWindow) { 47 | // contentWindow is the remote page's window object 48 | expect(typeof contentWindow === "object").to.be.true; 49 | }, 50 | onLoad(contentWindow) { 51 | // contentWindow is the remote page's window object 52 | expect(typeof contentWindow === "object").to.be.true; 53 | }, 54 | }); 55 | }); 56 | }); 57 | -------------------------------------------------------------------------------- /cypress/integration/2-advanced-examples/viewport.spec.js: -------------------------------------------------------------------------------- 1 | /// 2 | 3 | context("Viewport", () => { 4 | beforeEach(() => { 5 | cy.visit("https://example.cypress.io/commands/viewport"); 6 | }); 7 | 8 | it("cy.viewport() - set the viewport size and dimension", () => { 9 | // https://on.cypress.io/viewport 10 | 11 | cy.get("#navbar").should("be.visible"); 12 | cy.viewport(320, 480); 13 | 14 | // the navbar should have collapse since our screen is smaller 15 | cy.get("#navbar").should("not.be.visible"); 16 | cy.get(".navbar-toggle").should("be.visible").click(); 17 | cy.get(".nav").find("a").should("be.visible"); 18 | 19 | // lets see what our app looks like on a super large screen 20 | cy.viewport(2999, 2999); 21 | 22 | // cy.viewport() accepts a set of preset sizes 23 | // to easily set the screen to a device's width and height 24 | 25 | // We added a cy.wait() between each viewport change so you can see 26 | // the change otherwise it is a little too fast to see :) 27 | 28 | cy.viewport("macbook-15"); 29 | cy.wait(200); 30 | cy.viewport("macbook-13"); 31 | cy.wait(200); 32 | cy.viewport("macbook-11"); 33 | cy.wait(200); 34 | cy.viewport("ipad-2"); 35 | cy.wait(200); 36 | cy.viewport("ipad-mini"); 37 | cy.wait(200); 38 | cy.viewport("iphone-6+"); 39 | cy.wait(200); 40 | cy.viewport("iphone-6"); 41 | cy.wait(200); 42 | cy.viewport("iphone-5"); 43 | cy.wait(200); 44 | cy.viewport("iphone-4"); 45 | cy.wait(200); 46 | cy.viewport("iphone-3"); 47 | cy.wait(200); 48 | 49 | // cy.viewport() accepts an orientation for all presets 50 | // the default orientation is 'portrait' 51 | cy.viewport("ipad-2", "portrait"); 52 | cy.wait(200); 53 | cy.viewport("iphone-4", "landscape"); 54 | cy.wait(200); 55 | 56 | // The viewport will be reset back to the default dimensions 57 | // in between tests (the default can be set in cypress.json) 58 | }); 59 | }); 60 | -------------------------------------------------------------------------------- /cypress/integration/2-advanced-examples/local_storage.spec.js: -------------------------------------------------------------------------------- 1 | /// 2 | 3 | context("Local Storage", () => { 4 | beforeEach(() => { 5 | cy.visit("https://example.cypress.io/commands/local-storage"); 6 | }); 7 | // Although local storage is automatically cleared 8 | // in between tests to maintain a clean state 9 | // sometimes we need to clear the local storage manually 10 | 11 | it("cy.clearLocalStorage() - clear all data in local storage", () => { 12 | // https://on.cypress.io/clearlocalstorage 13 | cy.get(".ls-btn") 14 | .click() 15 | .should(() => { 16 | expect(localStorage.getItem("prop1")).to.eq("red"); 17 | expect(localStorage.getItem("prop2")).to.eq("blue"); 18 | expect(localStorage.getItem("prop3")).to.eq("magenta"); 19 | }); 20 | 21 | // clearLocalStorage() yields the localStorage object 22 | cy.clearLocalStorage().should((ls) => { 23 | expect(ls.getItem("prop1")).to.be.null; 24 | expect(ls.getItem("prop2")).to.be.null; 25 | expect(ls.getItem("prop3")).to.be.null; 26 | }); 27 | 28 | cy.get(".ls-btn") 29 | .click() 30 | .should(() => { 31 | expect(localStorage.getItem("prop1")).to.eq("red"); 32 | expect(localStorage.getItem("prop2")).to.eq("blue"); 33 | expect(localStorage.getItem("prop3")).to.eq("magenta"); 34 | }); 35 | 36 | // Clear key matching string in Local Storage 37 | cy.clearLocalStorage("prop1").should((ls) => { 38 | expect(ls.getItem("prop1")).to.be.null; 39 | expect(ls.getItem("prop2")).to.eq("blue"); 40 | expect(ls.getItem("prop3")).to.eq("magenta"); 41 | }); 42 | 43 | cy.get(".ls-btn") 44 | .click() 45 | .should(() => { 46 | expect(localStorage.getItem("prop1")).to.eq("red"); 47 | expect(localStorage.getItem("prop2")).to.eq("blue"); 48 | expect(localStorage.getItem("prop3")).to.eq("magenta"); 49 | }); 50 | 51 | // Clear keys matching regex in Local Storage 52 | cy.clearLocalStorage(/prop1|2/).should((ls) => { 53 | expect(ls.getItem("prop1")).to.be.null; 54 | expect(ls.getItem("prop2")).to.be.null; 55 | expect(ls.getItem("prop3")).to.eq("magenta"); 56 | }); 57 | }); 58 | }); 59 | -------------------------------------------------------------------------------- /styles/Home.module.css: -------------------------------------------------------------------------------- 1 | .container { 2 | padding: 0 2rem; 3 | } 4 | 5 | .main { 6 | min-height: 100vh; 7 | padding: 4rem 0; 8 | flex: 1; 9 | display: flex; 10 | flex-direction: column; 11 | justify-content: center; 12 | align-items: center; 13 | } 14 | 15 | .footer { 16 | display: flex; 17 | flex: 1; 18 | padding: 2rem 0; 19 | border-top: 1px solid #eaeaea; 20 | justify-content: center; 21 | align-items: center; 22 | } 23 | 24 | .footer a { 25 | display: flex; 26 | justify-content: center; 27 | align-items: center; 28 | flex-grow: 1; 29 | } 30 | 31 | .title a { 32 | color: #0070f3; 33 | text-decoration: none; 34 | } 35 | 36 | .title a:hover, 37 | .title a:focus, 38 | .title a:active { 39 | text-decoration: underline; 40 | } 41 | 42 | .title { 43 | margin: 0; 44 | line-height: 1.15; 45 | font-size: 4rem; 46 | } 47 | 48 | .title, 49 | .description { 50 | text-align: center; 51 | } 52 | 53 | .description { 54 | margin: 4rem 0; 55 | line-height: 1.5; 56 | font-size: 1.5rem; 57 | } 58 | 59 | .code { 60 | background: #fafafa; 61 | border-radius: 5px; 62 | padding: 0.75rem; 63 | font-size: 1.1rem; 64 | font-family: Menlo, Monaco, Lucida Console, Liberation Mono, DejaVu Sans Mono, 65 | Bitstream Vera Sans Mono, Courier New, monospace; 66 | } 67 | 68 | .grid { 69 | display: flex; 70 | align-items: center; 71 | justify-content: center; 72 | flex-wrap: wrap; 73 | max-width: 800px; 74 | } 75 | 76 | .card { 77 | margin: 1rem; 78 | padding: 1.5rem; 79 | text-align: left; 80 | color: inherit; 81 | text-decoration: none; 82 | border: 1px solid #eaeaea; 83 | border-radius: 10px; 84 | transition: color 0.15s ease, border-color 0.15s ease; 85 | max-width: 300px; 86 | } 87 | 88 | .card:hover, 89 | .card:focus, 90 | .card:active { 91 | color: #0070f3; 92 | border-color: #0070f3; 93 | } 94 | 95 | .card h2 { 96 | margin: 0 0 1rem 0; 97 | font-size: 1.5rem; 98 | } 99 | 100 | .card p { 101 | margin: 0; 102 | font-size: 1.25rem; 103 | line-height: 1.5; 104 | } 105 | 106 | .logo { 107 | height: 1em; 108 | margin-left: 0.5rem; 109 | } 110 | 111 | @media (max-width: 600px) { 112 | .grid { 113 | width: 100%; 114 | flex-direction: column; 115 | } 116 | } 117 | -------------------------------------------------------------------------------- /utils/lib/deferNextScript.js: -------------------------------------------------------------------------------- 1 | // eslint-disable-next-line @next/next/no-document-import-in-page 2 | import { NextScript } from "next/document"; 3 | import Script from "next/script"; 4 | 5 | function dedupe(bundles) { 6 | const files = new Set(); 7 | const kept = []; 8 | 9 | for (const bundle of bundles) { 10 | if (files.has(bundle.file)) continue; 11 | files.add(bundle.file); 12 | kept.push(bundle); 13 | } 14 | return kept; 15 | } 16 | 17 | class DeferNextScript extends NextScript { 18 | getDynamicChunks(files) { 19 | const { 20 | dynamicImports, 21 | assetPrefix, 22 | isDevelopment, 23 | devOnlyCacheBusterQueryString, 24 | } = this.context; 25 | 26 | return dedupe(dynamicImports).map((bundle) => { 27 | if (!bundle.file.endsWith(".js") || files.allFiles.includes(bundle.file)) 28 | return null; 29 | 30 | return ( 31 |