├── public ├── robots.txt └── site.webmanifest ├── next-env.d.ts ├── src ├── components │ └── Page │ │ ├── index.ts │ │ └── Page.tsx ├── assets │ ├── styles │ │ ├── mq.ts │ │ ├── types.ts │ │ ├── theme.ts │ │ └── globalStyles.tsx │ └── svg │ │ └── Logo.tsx └── pages │ ├── _app.tsx │ ├── index.tsx │ └── _document.tsx ├── installer ├── modules │ ├── handleError.js │ ├── clearConsole.js │ ├── printNextSteps.js │ └── run.js ├── packages │ └── package.json └── index.js ├── .gitignore ├── .editorconfig ├── .prettierrc ├── next.config.js ├── tsconfig.json ├── README.md ├── package.json └── LICENSE /public/robots.txt: -------------------------------------------------------------------------------- 1 | User-Agent: * 2 | Allow: * 3 | -------------------------------------------------------------------------------- /next-env.d.ts: -------------------------------------------------------------------------------- 1 | /// 2 | /// 3 | -------------------------------------------------------------------------------- /src/components/Page/index.ts: -------------------------------------------------------------------------------- 1 | export { 2 | Page, 3 | appleTouchIcon, 4 | favIcon32, 5 | favIcon16, 6 | favIcon, 7 | safariPinnedTab, 8 | preview, 9 | } from "./Page"; 10 | -------------------------------------------------------------------------------- /installer/modules/handleError.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Error handler 3 | */ 4 | 5 | const handleError = (err) => { 6 | if (err) { 7 | console.log("ERROR: " + err); 8 | } 9 | }; 10 | 11 | export { handleError }; 12 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | logs 2 | *.log* 3 | pids 4 | *.pid 5 | *.seed 6 | lib-cov 7 | coverage 8 | node_modules 9 | .vscode 10 | .DS_Store 11 | .next 12 | scratch.js 13 | notes.md 14 | .now 15 | .env 16 | .vercel 17 | out 18 | .eslintcache 19 | -------------------------------------------------------------------------------- /.editorconfig: -------------------------------------------------------------------------------- 1 | root = true 2 | 3 | [*] 4 | end_of_line = lf 5 | charset = utf-8 6 | trim_trailing_whitespace = true 7 | insert_final_newline = true 8 | indent_style = tab 9 | indent_size = 3 10 | 11 | [*.md] 12 | trim_trailing_whitespace = false 13 | -------------------------------------------------------------------------------- /.prettierrc: -------------------------------------------------------------------------------- 1 | { 2 | "printWidth": 80, 3 | "useTabs": true, 4 | "tabWidth": 4, 5 | "endOfLine": "lf", 6 | "semi": true, 7 | "singleQuote": false, 8 | "trailingComma": "all", 9 | "bracketSpacing": true, 10 | "bracketSameLine": false, 11 | "arrowParens": "always" 12 | } 13 | -------------------------------------------------------------------------------- /installer/modules/clearConsole.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Cross platform clear console. 3 | * 4 | * Support for win32 and others. 5 | */ 6 | 7 | const clearConsole = () => { 8 | process.stdout.write( 9 | "win32" === process.platform 10 | ? "\x1B[2J\x1B[0f" 11 | : "\x1B[2J\x1B[3J\x1B[H", 12 | ); 13 | }; 14 | 15 | export { clearConsole }; 16 | -------------------------------------------------------------------------------- /src/assets/styles/mq.ts: -------------------------------------------------------------------------------- 1 | import { theme } from "./theme"; 2 | const breakpoints = theme.spacing.breakpoints; 3 | 4 | const Breakpoints = { 5 | xs: 0, 6 | sm: 1, 7 | md: 2, 8 | lg: 3, 9 | xl: 4, 10 | xxl: 5, 11 | xxxl: 6, 12 | }; 13 | 14 | function mq(minWidth) { 15 | return `@media screen and (min-width: ${breakpoints[minWidth]}px)`; 16 | } 17 | 18 | export { mq, Breakpoints }; 19 | -------------------------------------------------------------------------------- /next.config.js: -------------------------------------------------------------------------------- 1 | const withBundleAnalyzer = require("@next/bundle-analyzer"); 2 | 3 | const config = { 4 | compiler: { 5 | emotion: true, 6 | }, 7 | }; 8 | 9 | const bundleAnalyzer = withBundleAnalyzer({ 10 | enabled: process.env.ANALYZE === "true", 11 | }); 12 | 13 | module.exports = (_phase, { defaultConfig }) => { 14 | const plugins = [bundleAnalyzer]; 15 | return plugins.reduce((acc, plugin) => plugin(acc), { ...config }); 16 | }; 17 | -------------------------------------------------------------------------------- /src/pages/_app.tsx: -------------------------------------------------------------------------------- 1 | import React from "react"; 2 | import { ThemeProvider } from "@emotion/react"; 3 | import { globalStyles } from "../assets/styles/globalStyles"; 4 | import { theme } from "../assets/styles/theme"; 5 | 6 | function App({ Component, pageProps }) { 7 | return ( 8 | <> 9 | 10 | {globalStyles} 11 | 12 | 13 | 14 | ); 15 | } 16 | 17 | export default App; 18 | -------------------------------------------------------------------------------- /public/site.webmanifest: -------------------------------------------------------------------------------- 1 | { 2 | "name": "Nextify", 3 | "short_name": "Nextify", 4 | "icons": [ 5 | { 6 | "src": "https://nextify.s3-eu-west-1.amazonaws.com/img/meta/192.png", 7 | "sizes": "192x192", 8 | "type": "image/png" 9 | }, 10 | { 11 | "src": "https://nextify.s3-eu-west-1.amazonaws.com/img/meta/512.png", 12 | "sizes": "512x512", 13 | "type": "image/png" 14 | } 15 | ], 16 | "theme_color": "#000000", 17 | "background_color": "#000000", 18 | "display": "standalone" 19 | } 20 | -------------------------------------------------------------------------------- /tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "target": "es5", 4 | "lib": ["dom", "dom.iterable", "esnext"], 5 | "allowJs": true, 6 | "skipLibCheck": true, 7 | "strict": false, 8 | "forceConsistentCasingInFileNames": true, 9 | "noEmit": true, 10 | "esModuleInterop": true, 11 | "module": "esnext", 12 | "moduleResolution": "node", 13 | "resolveJsonModule": true, 14 | "isolatedModules": true, 15 | "jsx": "preserve", 16 | "types": ["@emotion/react/types/css-prop"], 17 | "baseUrl": "./src", 18 | "incremental": true 19 | }, 20 | "include": ["next-env.d.ts", "**/*.ts", "**/*.tsx", "next.config.js"], 21 | "exclude": ["node_modules"] 22 | } 23 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # [![Nextify Logo](https://nextify.s3-eu-west-1.amazonaws.com/img/nextify-repository-logo.svg#1)](https://www.nextify.me/) 2 | 3 | [![Version](https://img.shields.io/github/package-json/v/luangjokaj/nextify)](https://www.fuzzymail.co/) 4 | 5 | React apps using Next.js and Emotion. 6 | 7 | --- 8 | 9 | ## Documentation 10 | 11 | For full documentation, visit https://www.nextify.me. 12 | 13 | ## Community 14 | 15 | For help, discussion about best practices, or any other conversation that would benefit from being searchable: 16 | 17 | [Discuss Nextify on GitHub](https://github.com/luangjokaj/nextify/discussions) 18 | 19 | For casual chit-chat with others using Nextify: 20 | 21 | [Join the Discord Server](https://discord.com/invite/uQFdMddMZw) 22 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "create-nextify-app", 3 | "version": "0.0.2-21", 4 | "description": "React apps using Next.js and Emotion.", 5 | "keywords": [ 6 | "nextjs", 7 | "next", 8 | "react", 9 | "javascript", 10 | "typescript", 11 | "ts", 12 | "framework", 13 | "emotion", 14 | "styles", 15 | "styling", 16 | "css", 17 | "css-in-js", 18 | "workflow" 19 | ], 20 | "homepage": "https://www.nextify.me", 21 | "repository": "https://github.com/luangjokaj/nextify", 22 | "exports": "./installer/index.js", 23 | "type": "module", 24 | "node": "^12.20.0 || ^14.13.1 || >=16.0.0", 25 | "bin": { 26 | "create-nextify-app": "./installer/index.js" 27 | }, 28 | "author": "Luan Gjokaj ", 29 | "license": "MIT", 30 | "dependencies": { 31 | "chalk": "^5.2.0", 32 | "commander": "^10.0.0", 33 | "download": "^8.0.0", 34 | "execa": "^6.1.0", 35 | "ora": "^6.1.2", 36 | "prompts": "^2.4.2" 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /src/pages/index.tsx: -------------------------------------------------------------------------------- 1 | import React from "react"; 2 | import { css } from "@emotion/react"; 3 | import { Container, H1, Space } from "cherry-components"; 4 | import { Page } from "../components/Page"; 5 | import { Logo } from "../assets/svg/Logo"; 6 | 7 | function Index() { 8 | return ( 9 | 10 | 11 | 12 |

13 | 14 |

15 | 16 |
css` 18 | padding: 32px; 19 | background-color: ${theme.colors.primary}; 20 | color: ${theme.colors.light}; 21 | font-size: ${theme.sizes.h4.size.desktop}; 22 | border-radius: 12px; 23 | transition: all 0.3s ease; 24 | 25 | &:hover { 26 | background-color: ${theme.colors.primaryDark}; 27 | } 28 | `} 29 | > 30 | Hello world. 31 |
32 |
33 |
34 | ); 35 | } 36 | 37 | export default Index; 38 | -------------------------------------------------------------------------------- /src/pages/_document.tsx: -------------------------------------------------------------------------------- 1 | import React from "react"; 2 | import { Html, Head, Main, NextScript } from "next/document"; 3 | 4 | function Document() { 5 | return ( 6 | 7 | 8 | 13 | 18 | 23 | 29 | 30 | 31 |
32 | 33 | 34 | 35 | ); 36 | } 37 | 38 | export default Document; 39 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) Luan Gjokaj - www.riangle.com 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 | -------------------------------------------------------------------------------- /installer/packages/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "create-nextify-app", 3 | "version": "0.0.2-21", 4 | "description": "React apps using Next.js and Emotion.", 5 | "keywords": [ 6 | "nextjs", 7 | "next", 8 | "react", 9 | "javascript", 10 | "typescript", 11 | "ts", 12 | "framework", 13 | "emotion", 14 | "styles", 15 | "css", 16 | "styling", 17 | "css-in-js", 18 | "workflow" 19 | ], 20 | "homepage": "https://www.nextify.me", 21 | "repository": "https://github.com/luangjokaj/nextify", 22 | "exports": "./index.js", 23 | "scripts": { 24 | "dev": "next dev", 25 | "build": "next build", 26 | "start": "next start", 27 | "export": "next export", 28 | "lint": "next lint", 29 | "type-check": "tsc", 30 | "type-watch": "tsc --watch", 31 | "format": "prettier --write \"./**/*.{js,json,ts,tsx}\" \"!.node_modules/**\" \"!.next/**\"", 32 | "analyze": "ANALYZE=true next build", 33 | "analyze:server": "BUNDLE_ANALYZE=server next build", 34 | "analyze:browser": "BUNDLE_ANALYZE=browser next build" 35 | }, 36 | "author": "Luan Gjokaj ", 37 | "license": "MIT", 38 | "dependencies": { 39 | "@emotion/babel-plugin": "^11.10.5", 40 | "@emotion/react": "^11.10.5", 41 | "@next/bundle-analyzer": "^13.1.3", 42 | "@types/node": "^18.11.18", 43 | "@types/react": "^18.0.27", 44 | "@types/react-dom": "^18.0.10", 45 | "cherry-components": "^0.0.2-21", 46 | "express": "^4.18.2", 47 | "next": "^13.1.3", 48 | "prettier": "^2.8.3", 49 | "react": "^18.2.0", 50 | "react-dom": "^18.2.0", 51 | "typescript": "^4.9.4" 52 | } 53 | } 54 | -------------------------------------------------------------------------------- /installer/index.js: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env node 2 | /** 3 | * Main Installer for Nextify 4 | * Check the node version if above 12 then run the app. 5 | * 6 | * Credits: 7 | * Ahmad Awais - https://twitter.com/MrAhmadAwais/ 8 | * Luan Gjokaj - https://twitter.com/luangjokaj/ 9 | */ 10 | 11 | import prompts from "prompts"; 12 | import chalk from "chalk"; 13 | import { program } from "commander"; 14 | import { createRequire } from "module"; 15 | import { run } from "./modules/run.js"; 16 | 17 | const require = createRequire(import.meta.url); 18 | const packageData = require("./packages/package.json"); 19 | 20 | const version = packageData.version; 21 | const currentNodeVersion = process.versions.node; 22 | const semver = currentNodeVersion.split("."); 23 | const major = semver[0]; 24 | 25 | program 26 | .version(version, "-v, --vers", "output the current version") 27 | .parse(process.argv); 28 | 29 | (async () => { 30 | const response = await prompts({ 31 | type: "confirm", 32 | name: "value", 33 | message: `Do you want to install ${chalk.white.bgBlue( 34 | "⚡ Nextify", 35 | )} in the current directory?\n${chalk.red(process.cwd())}`, 36 | }); 37 | 38 | if (response.value) { 39 | // If below Node 12 40 | if (12 > major) { 41 | console.error( 42 | chalk.red( 43 | "You are running Node " + 44 | currentNodeVersion + 45 | ".\n" + 46 | "Install Nextify requires Node 12 or higher. \n" + 47 | "Kindly, update your version of Node.", 48 | ), 49 | ); 50 | process.exit(1); 51 | } 52 | 53 | // Makes the script crash on unhandled rejections instead of silently 54 | // ignoring them. In the future, promise rejections that are not handled will 55 | // terminate the Node.js process with a non-zero exit code 56 | process.on("unhandledRejection", (err) => { 57 | throw err; 58 | }); 59 | 60 | /** 61 | * Run the entire program 62 | * 63 | * Runs all the functions with async/await 64 | */ 65 | run(); 66 | } 67 | })(); 68 | -------------------------------------------------------------------------------- /src/components/Page/Page.tsx: -------------------------------------------------------------------------------- 1 | import React from "react"; 2 | import Head from "next/head"; 3 | 4 | export const appleTouchIcon = 5 | "https://nextify.s3-eu-west-1.amazonaws.com/img/meta/180.png"; 6 | export const favIcon32 = 7 | "https://nextify.s3-eu-west-1.amazonaws.com/img/meta/32.png"; 8 | export const favIcon16 = 9 | "https://nextify.s3-eu-west-1.amazonaws.com/img/meta/16.png"; 10 | export const favIcon = 11 | "https://nextify.s3-eu-west-1.amazonaws.com/img/meta/favicon.ico"; 12 | export const safariPinnedTab = 13 | "https://nextify.s3-eu-west-1.amazonaws.com/img/meta/512.svg"; 14 | export const preview = 15 | "https://nextify.s3-eu-west-1.amazonaws.com/img/meta/preview.jpg"; 16 | 17 | const Page = ({ 18 | title = "Nextify", 19 | description = "React apps using Next.js and Emotion.", 20 | image = preview, 21 | children, 22 | }) => ( 23 | 24 | 25 | 26 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 45 | 46 | 47 | 48 | 49 | {title + " - Nextify"} 50 | 51 | {children} 52 | 53 | ); 54 | 55 | export { Page }; 56 | -------------------------------------------------------------------------------- /installer/modules/printNextSteps.js: -------------------------------------------------------------------------------- 1 | import chalk from "chalk"; 2 | 3 | const printNextSteps = () => { 4 | console.log("\n\n✅ ", chalk.black.bgGreen(" All done! Happy coding. \n")); 5 | console.log( 6 | "Installer has added ⚡ Nextify files to the current directory. ", 7 | "\nInside this directory, you can run this command:", 8 | ); 9 | 10 | // Scripts 11 | console.log( 12 | "\n👉 ", 13 | " Type", 14 | chalk.black.bgWhite(" npm run dev "), 15 | "\n\n", 16 | " Use to compile and run your files.", 17 | "\n", 18 | " Watches for any changes and reports back any errors in your code.", 19 | ); 20 | 21 | // Support 22 | console.log("\n✊ ", chalk.black.bgYellow(" Support Nextify \n")); 23 | console.log( 24 | "Like Nextify? Check out our other free and open source repositories: \n", 25 | ); 26 | console.log( 27 | ` ${chalk.yellow("Cherry → ")} https://bit.ly/3sEr75P`, 28 | "\n", 29 | ` ${chalk.gray("• A design system to build the web.")}`, 30 | "\n", 31 | ` ${chalk.yellow("GoPablo → ")} http://bit.ly/2Hgkfpy`, 32 | "\n", 33 | ` ${chalk.gray("• Create optimized static websites.")}`, 34 | "\n", 35 | ` ${chalk.yellow("WordPressify → ")} https://bit.ly/2KTqyQX`, 36 | "\n", 37 | ` ${chalk.gray("• Automate your WordPress development workflow.")}`, 38 | "\n", 39 | ` ${chalk.yellow("Nextify → ")} https://bit.ly/3m4lVWm`, 40 | "\n", 41 | ` ${chalk.gray("• React apps using Next.js and Emotion.")}`, 42 | "\n", 43 | ` ${chalk.yellow("FuzzyMail → ")} https://bit.ly/2P3Irlr`, 44 | "\n", 45 | ` ${chalk.gray("• Responsive email template generator.")}`, 46 | "\n", 47 | ` ${chalk.green("Powered by Riangle → ")} https://bit.ly/2P5i26I`, 48 | "\n", 49 | "\n", 50 | ` ${chalk.red( 51 | "Thank you for using ⚡ Nextify → ", 52 | )} https://www.nextify.me`, 53 | ); 54 | 55 | // Get started 56 | console.log("\n\n🎯 ", chalk.black.bgGreen(" Get Started → \n")); 57 | console.log(" You can start: \n"); 58 | console.log( 59 | ` ${chalk.dim("1.")} Editing your new react application: ${chalk.green( 60 | `${process.cwd()}/src`, 61 | )}`, 62 | ); 63 | console.log( 64 | ` ${chalk.dim("2.")} Running: ${chalk.green("npm")} run dev`, 65 | "\n\n", 66 | ); 67 | process.exit(); 68 | }; 69 | 70 | export { printNextSteps }; 71 | -------------------------------------------------------------------------------- /src/assets/styles/types.ts: -------------------------------------------------------------------------------- 1 | import { Theme as EmotionTheme } from "@emotion/react"; 2 | 3 | interface ResponsiveSize { 4 | mobile: TString; 5 | desktop: TString; 6 | } 7 | 8 | interface RowColSize { 9 | default: TString; 10 | medium: TString; 11 | big: TString; 12 | } 13 | 14 | export interface Breakpoints { 15 | xs: TNumber; 16 | sm: TNumber; 17 | md: TNumber; 18 | lg: TNumber; 19 | xl: TNumber; 20 | xxl: TNumber; 21 | xxxl: TNumber; 22 | } 23 | 24 | export interface Spacing { 25 | maxWidth: TString; 26 | maxWidthLimit: TString; 27 | paddingTopBody: ResponsiveSize; 28 | marginContainer: ResponsiveSize; 29 | marginRow: RowColSize; 30 | gutterCol: RowColSize; 31 | breakpoints: [number, number, number, number, number, number, number]; 32 | } 33 | 34 | export interface Colors { 35 | primaryLight: TString; 36 | primary: TString; 37 | primaryDark: TString; 38 | 39 | secondaryLight: TString; 40 | secondary: TString; 41 | secondaryDark: TString; 42 | 43 | tertiaryLight: TString; 44 | tertiary: TString; 45 | tertiaryDark: TString; 46 | 47 | dark: TString; 48 | light: TString; 49 | 50 | grayLight: TString; 51 | gray: TString; 52 | grayDark: TString; 53 | 54 | success: TString; 55 | error: TString; 56 | warning: TString; 57 | info: TString; 58 | } 59 | 60 | export interface Fonts { 61 | text: TString; 62 | head: TString; 63 | special: TString; 64 | mono: TString; 65 | } 66 | 67 | export interface FontSizes { 68 | hero1: { 69 | size: ResponsiveSize; 70 | lineheight: ResponsiveSize; 71 | }; 72 | hero2: { 73 | size: ResponsiveSize; 74 | lineheight: ResponsiveSize; 75 | }; 76 | hero3: { 77 | size: ResponsiveSize; 78 | lineheight: ResponsiveSize; 79 | }; 80 | h1: { 81 | size: ResponsiveSize; 82 | lineheight: ResponsiveSize; 83 | }; 84 | h2: { 85 | size: ResponsiveSize; 86 | lineheight: ResponsiveSize; 87 | }; 88 | h3: { 89 | size: ResponsiveSize; 90 | lineheight: ResponsiveSize; 91 | }; 92 | h4: { 93 | size: ResponsiveSize; 94 | lineheight: ResponsiveSize; 95 | }; 96 | h5: { 97 | size: ResponsiveSize; 98 | lineheight: ResponsiveSize; 99 | }; 100 | h6: { 101 | size: ResponsiveSize; 102 | lineheight: ResponsiveSize; 103 | }; 104 | eyebrow: { 105 | size: ResponsiveSize; 106 | lineheight: ResponsiveSize; 107 | }; 108 | subtitle: { 109 | size: ResponsiveSize; 110 | lineheight: ResponsiveSize; 111 | }; 112 | button: { 113 | size: ResponsiveSize; 114 | lineheight: ResponsiveSize; 115 | }; 116 | buttonBig: { 117 | size: ResponsiveSize; 118 | lineheight: ResponsiveSize; 119 | }; 120 | lead: { 121 | size: ResponsiveSize; 122 | lineheight: ResponsiveSize; 123 | }; 124 | input: { 125 | size: ResponsiveSize; 126 | lineheight: ResponsiveSize; 127 | }; 128 | inputBig: { 129 | size: ResponsiveSize; 130 | lineheight: ResponsiveSize; 131 | }; 132 | strong: { 133 | size: ResponsiveSize; 134 | lineheight: ResponsiveSize; 135 | }; 136 | text: { 137 | size: ResponsiveSize; 138 | lineheight: ResponsiveSize; 139 | }; 140 | small: { 141 | size: ResponsiveSize; 142 | lineheight: ResponsiveSize; 143 | }; 144 | blockquote: { 145 | size: ResponsiveSize; 146 | lineheight: ResponsiveSize; 147 | }; 148 | } 149 | 150 | export interface Theme extends EmotionTheme { 151 | isDark?: boolean; 152 | spacing?: Spacing; 153 | colors?: Colors; 154 | fonts?: Fonts; 155 | sizes?: FontSizes; 156 | } 157 | 158 | export interface ThemeProps { 159 | theme: Theme; 160 | } 161 | 162 | export interface ThemeProviderProps { 163 | children: React.ReactNode; 164 | theme: Theme; 165 | } 166 | -------------------------------------------------------------------------------- /installer/modules/run.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Installation 3 | */ 4 | 5 | import fs from "fs"; 6 | import ora from "ora"; 7 | import chalk from "chalk"; 8 | import download from "download"; 9 | import { execa } from "execa"; 10 | import { createRequire } from "module"; 11 | import { handleError } from "./handleError.js"; 12 | import { clearConsole } from "./clearConsole.js"; 13 | import { printNextSteps } from "./printNextSteps.js"; 14 | 15 | const require = createRequire(import.meta.url); 16 | const packageData = require("../packages/package.json"); 17 | 18 | const version = packageData.version; 19 | 20 | const theCWD = process.cwd(); 21 | const theCWDArray = theCWD.split("/"); 22 | const theDir = theCWDArray[theCWDArray.length - 1]; 23 | 24 | const run = () => { 25 | // Init 26 | clearConsole(); 27 | 28 | let upstreamUrl = `https://raw.githubusercontent.com/luangjokaj/nextify/v${version}`; 29 | 30 | // Files 31 | const filesToDownload = [ 32 | `${upstreamUrl}/.editorconfig`, 33 | `${upstreamUrl}/.gitignore`, 34 | `${upstreamUrl}/.prettierrc`, 35 | `${upstreamUrl}/LICENSE`, 36 | `${upstreamUrl}/next.config.js`, 37 | `${upstreamUrl}/installer/packages/package.json`, 38 | `${upstreamUrl}/README.md`, 39 | `${upstreamUrl}/tsconfig.json`, 40 | 41 | `${upstreamUrl}/public/robots.txt`, 42 | `${upstreamUrl}/public/site.webmanifest`, 43 | 44 | `${upstreamUrl}/src/assets/styles/globalStyles.tsx`, 45 | `${upstreamUrl}/src/assets/styles/mq.ts`, 46 | `${upstreamUrl}/src/assets/styles/theme.ts`, 47 | 48 | `${upstreamUrl}/src/assets/svg/Logo.tsx`, 49 | 50 | `${upstreamUrl}/src/components/Page/index.ts`, 51 | `${upstreamUrl}/src/components/Page/Page.tsx`, 52 | 53 | `${upstreamUrl}/src/pages/_app.tsx`, 54 | `${upstreamUrl}/src/pages/_document.tsx`, 55 | `${upstreamUrl}/src/pages/index.tsx`, 56 | ]; 57 | 58 | // Organise file structure 59 | const dotFiles = [".editorconfig", ".gitignore", ".prettierrc"]; 60 | const publicFiles = ["robots.txt", "site.webmanifest"]; 61 | const stylesFiles = ["globalStyles.tsx", "mq.ts", "theme.ts"]; 62 | const svgFiles = ["Logo.tsx"]; 63 | const componentsFiles = ["index.ts", "Page.tsx"]; 64 | const pagesFiles = ["_app.tsx", "_document.tsx", "index.tsx"]; 65 | 66 | // Start 67 | console.log("\n"); 68 | console.log( 69 | "📦 ", 70 | chalk.black.bgYellow( 71 | ` Downloading ⚡ Nextify files in: → ${chalk.bgGreen( 72 | ` ${theDir} `, 73 | )}\n`, 74 | ), 75 | chalk.dim(`\n In the directory: ${theCWD}\n`), 76 | chalk.dim("This might take a couple of minutes.\n"), 77 | ); 78 | 79 | const spinner = ora({ text: "" }); 80 | spinner.start( 81 | `1. Creating ⚡ Nextify files inside → ${chalk.black.bgWhite( 82 | ` ${theDir} `, 83 | )}`, 84 | ); 85 | 86 | // Download 87 | Promise.all(filesToDownload.map((x) => download(x, `${theCWD}`))).then( 88 | async () => { 89 | if (!fs.existsSync("src")) { 90 | await execa("mkdir", [ 91 | "public", 92 | "src", 93 | "src/assets", 94 | "src/assets/styles", 95 | "src/assets/svg", 96 | "src/components", 97 | "src/components/Page", 98 | "src/pages", 99 | ]); 100 | } 101 | 102 | dotFiles.map((x) => 103 | fs.rename(`${theCWD}/${x.slice(1)}`, `${theCWD}/${x}`, (err) => 104 | handleError(err), 105 | ), 106 | ); 107 | publicFiles.map((x) => 108 | fs.rename(`${theCWD}/${x}`, `${theCWD}/public/${x}`, (err) => 109 | handleError(err), 110 | ), 111 | ); 112 | stylesFiles.map((x) => 113 | fs.rename( 114 | `${theCWD}/${x}`, 115 | `${theCWD}/src/assets/styles/${x}`, 116 | (err) => handleError(err), 117 | ), 118 | ); 119 | svgFiles.map((x) => 120 | fs.rename( 121 | `${theCWD}/${x}`, 122 | `${theCWD}/src/assets/svg/${x}`, 123 | (err) => handleError(err), 124 | ), 125 | ); 126 | componentsFiles.map((x) => 127 | fs.rename( 128 | `${theCWD}/${x}`, 129 | `${theCWD}/src/components/Page/${x}`, 130 | (err) => handleError(err), 131 | ), 132 | ); 133 | pagesFiles.map((x) => 134 | fs.rename(`${theCWD}/${x}`, `${theCWD}/src/pages/${x}`, (err) => 135 | handleError(err), 136 | ), 137 | ); 138 | spinner.succeed(); 139 | 140 | // The npm install 141 | spinner.start("2. Installing npm packages..."); 142 | await execa("npm", ["install", "--legacy-peer-deps"]); 143 | spinner.succeed(); 144 | 145 | // Done 146 | printNextSteps(); 147 | }, 148 | ); 149 | }; 150 | 151 | export { run }; 152 | -------------------------------------------------------------------------------- /src/assets/svg/Logo.tsx: -------------------------------------------------------------------------------- 1 | import React from "react"; 2 | 3 | function Logo() { 4 | return ( 5 | 12 | 16 | 20 | 24 | 28 | 34 | 38 | 42 | 48 | 52 | 56 | 60 | 61 | ); 62 | } 63 | 64 | export { Logo }; 65 | -------------------------------------------------------------------------------- /src/assets/styles/theme.ts: -------------------------------------------------------------------------------- 1 | const theme = { 2 | spacing: { 3 | maxWidth: "1280px", 4 | maxWidthLimit: "1440px", 5 | paddingTopBody: { mobile: "0", desktop: "0" }, 6 | marginContainer: { mobile: "20px", desktop: "20px" }, 7 | marginRow: { default: "-10px", medium: "-30px", big: "-50px" }, 8 | gutterCol: { default: "10px", medium: "30px", big: "50px" }, 9 | breakpoints: [0, 576, 768, 992, 1200, 1440, 1920], 10 | }, 11 | colors: { 12 | primaryLight: "#98C7FF", 13 | primary: "#0370F3", 14 | primaryDark: "#003A80", 15 | 16 | secondaryLight: "#7DD3FC", 17 | secondary: "#0EA5E9", 18 | secondaryDark: "#075985", 19 | 20 | tertiaryLight: "#D8B4FE", 21 | tertiary: "#A855F7", 22 | tertiaryDark: "#6B21A8", 23 | 24 | dark: "#000", 25 | light: "#fff", 26 | 27 | grayLight: "#E5E7EB", 28 | gray: "#9CA3AF", 29 | grayDark: "#4B5563", 30 | 31 | success: "#28A745", 32 | error: "#DC3545", 33 | warning: "#FFC107", 34 | info: "#17A2B8", 35 | }, 36 | fonts: { 37 | text: "'Inter', sans-serif", 38 | head: "'Inter', sans-serif", 39 | special: "'Inter', sans-serif", 40 | mono: "'Inter', monospace", 41 | }, 42 | sizes: { 43 | hero1: { 44 | size: { 45 | mobile: "52px", 46 | desktop: "62px", 47 | }, 48 | lineheight: { 49 | mobile: "1.15", 50 | desktop: "1.15", 51 | }, 52 | }, 53 | hero2: { 54 | size: { 55 | mobile: "42px", 56 | desktop: "52px", 57 | }, 58 | lineheight: { 59 | mobile: "1.15", 60 | desktop: "1.15", 61 | }, 62 | }, 63 | hero3: { 64 | size: { 65 | mobile: "32px", 66 | desktop: "42px", 67 | }, 68 | lineheight: { 69 | mobile: "1.15", 70 | desktop: "1.15", 71 | }, 72 | }, 73 | h1: { 74 | size: { 75 | mobile: "38px", 76 | desktop: "40px", 77 | }, 78 | lineheight: { 79 | mobile: "1.2", 80 | desktop: "1.2", 81 | }, 82 | }, 83 | h2: { 84 | size: { 85 | mobile: "28px", 86 | desktop: "32px", 87 | }, 88 | lineheight: { 89 | mobile: "1.2", 90 | desktop: "1.2", 91 | }, 92 | }, 93 | h3: { 94 | size: { 95 | mobile: "24px", 96 | desktop: "28px", 97 | }, 98 | lineheight: { 99 | mobile: "1.2", 100 | desktop: "1.2", 101 | }, 102 | }, 103 | h4: { 104 | size: { 105 | mobile: "22px", 106 | desktop: "24px", 107 | }, 108 | lineheight: { 109 | mobile: "1.3", 110 | desktop: "1.3", 111 | }, 112 | }, 113 | h5: { 114 | size: { 115 | mobile: "18px", 116 | desktop: "20px", 117 | }, 118 | lineheight: { 119 | mobile: "1.4", 120 | desktop: "1.4", 121 | }, 122 | }, 123 | h6: { 124 | size: { 125 | mobile: "16px", 126 | desktop: "18px", 127 | }, 128 | lineheight: { 129 | mobile: "1.4", 130 | desktop: "1.4", 131 | }, 132 | }, 133 | eyebrow: { 134 | size: { 135 | mobile: "16px", 136 | desktop: "18px", 137 | }, 138 | lineheight: { 139 | mobile: "1.35", 140 | desktop: "1.15", 141 | }, 142 | }, 143 | subtitle: { 144 | size: { 145 | mobile: "18px", 146 | desktop: "20px", 147 | }, 148 | lineheight: { 149 | mobile: "1.35", 150 | desktop: "1.35", 151 | }, 152 | }, 153 | button: { 154 | size: { 155 | mobile: "12px", 156 | desktop: "14px", 157 | }, 158 | lineheight: { 159 | mobile: "1", 160 | desktop: "1", 161 | }, 162 | }, 163 | buttonBig: { 164 | size: { 165 | mobile: "16px", 166 | desktop: "18px", 167 | }, 168 | lineheight: { 169 | mobile: "1", 170 | desktop: "1", 171 | }, 172 | }, 173 | lead: { 174 | size: { 175 | mobile: "16px", 176 | desktop: "18px", 177 | }, 178 | lineheight: { 179 | mobile: "1.35", 180 | desktop: "1.35", 181 | }, 182 | }, 183 | input: { 184 | size: { 185 | mobile: "12px", 186 | desktop: "14px", 187 | }, 188 | lineheight: { 189 | mobile: "1", 190 | desktop: "1", 191 | }, 192 | }, 193 | inputBig: { 194 | size: { 195 | mobile: "16px", 196 | desktop: "18px", 197 | }, 198 | lineheight: { 199 | mobile: "1", 200 | desktop: "1", 201 | }, 202 | }, 203 | strong: { 204 | size: { 205 | mobile: "14px", 206 | desktop: "16px", 207 | }, 208 | lineheight: { 209 | mobile: "1.5", 210 | desktop: "1.5", 211 | }, 212 | }, 213 | text: { 214 | size: { 215 | mobile: "14px", 216 | desktop: "16px", 217 | }, 218 | lineheight: { 219 | mobile: "1.5", 220 | desktop: "1.5", 221 | }, 222 | }, 223 | small: { 224 | size: { 225 | mobile: "12px", 226 | desktop: "14px", 227 | }, 228 | lineheight: { 229 | mobile: "1.3", 230 | desktop: "1.3", 231 | }, 232 | }, 233 | blockquote: { 234 | size: { 235 | mobile: "16px", 236 | desktop: "18px", 237 | }, 238 | lineheight: { 239 | mobile: "1.5", 240 | desktop: "1.5", 241 | }, 242 | }, 243 | }, 244 | }; 245 | 246 | export { theme }; 247 | -------------------------------------------------------------------------------- /src/assets/styles/globalStyles.tsx: -------------------------------------------------------------------------------- 1 | import { Global, css } from "@emotion/react"; 2 | import { Breakpoints, mq } from "./mq"; 3 | 4 | const globalStyles = ( 5 | css` 7 | html, 8 | body { 9 | margin: 0; 10 | padding: 0; 11 | min-height: 100%; 12 | scroll-behavior: smooth; 13 | } 14 | 15 | body { 16 | -moz-osx-font-smoothing: grayscale; 17 | -webkit-text-size-adjust: 100%; 18 | -webkit-font-smoothing: antialiased; 19 | font-family: ${theme.fonts.text}; 20 | font-size: ${theme.sizes.text.size.mobile}; 21 | line-height: ${theme.sizes.text.lineheight.mobile}; 22 | padding-top: ${theme.spacing.paddingTopBody.mobile}; 23 | color: ${theme.colors.dark}; 24 | margin: 0; 25 | 26 | ${mq(Breakpoints.lg)} { 27 | font-size: ${theme.sizes.text.size.desktop}; 28 | line-height: ${theme.sizes.text.lineheight.desktop}; 29 | padding-top: ${theme.spacing.paddingTopBody.desktop}; 30 | } 31 | } 32 | 33 | * { 34 | box-sizing: border-box; 35 | 36 | &:before, 37 | &:after { 38 | box-sizing: border-box; 39 | } 40 | 41 | &::selection { 42 | background: ${theme.colors.primary}; 43 | color: ${theme.colors.light}; 44 | } 45 | } 46 | 47 | main { 48 | display: block; 49 | } 50 | 51 | hr { 52 | background: none; 53 | border: none; 54 | border-bottom: solid 1px ${theme.colors.grayLight}; 55 | box-sizing: content-box; 56 | height: 0; 57 | overflow: visible; 58 | margin: 10px 0; 59 | } 60 | 61 | pre, 62 | code, 63 | kbd, 64 | samp { 65 | font-family: monospace, monospace; 66 | } 67 | 68 | pre { 69 | border-radius: 12px; 70 | } 71 | 72 | small { 73 | font-size: ${theme.sizes.small.size.mobile}; 74 | line-height: ${theme.sizes.small.lineheight.mobile}; 75 | 76 | ${mq(Breakpoints.lg)} { 77 | font-size: ${theme.sizes.small.size.desktop}; 78 | line-height: ${theme.sizes.small.lineheight.desktop}; 79 | } 80 | } 81 | 82 | blockquote { 83 | margin: 10px 0; 84 | padding: 0; 85 | font-size: ${theme.sizes.blockquote.size.mobile}; 86 | line-height: ${theme.sizes.blockquote.lineheight.mobile}; 87 | 88 | ${mq(Breakpoints.lg)} { 89 | font-size: ${theme.sizes.blockquote.size.desktop}; 90 | line-height: ${theme.sizes.blockquote.lineheight.desktop}; 91 | } 92 | } 93 | 94 | sub, 95 | sup { 96 | font-size: 75%; 97 | line-height: 0; 98 | position: relative; 99 | vertical-align: baseline; 100 | } 101 | 102 | sub { 103 | bottom: -0.25em; 104 | } 105 | 106 | sup { 107 | top: -0.5em; 108 | } 109 | 110 | a, 111 | button { 112 | cursor: pointer; 113 | outline: none; 114 | text-decoration: none; 115 | transition: all 0.3s ease; 116 | } 117 | 118 | a { 119 | background-color: transparent; 120 | color: ${theme.colors.grayDark}; 121 | 122 | @media (hover: hover) { 123 | &:hover { 124 | color: ${theme.colors.primary}; 125 | } 126 | } 127 | } 128 | 129 | p { 130 | margin: 10px 0; 131 | 132 | & a { 133 | color: ${theme.colors.primary}; 134 | 135 | @media (hover: hover) { 136 | &:hover { 137 | color: ${theme.colors.primaryDark}; 138 | } 139 | } 140 | } 141 | } 142 | 143 | blockquote, 144 | p, 145 | ol, 146 | ul { 147 | color: ${theme.colors.gray}; 148 | } 149 | 150 | figure { 151 | margin: 0; 152 | } 153 | 154 | fieldset { 155 | appearance: none; 156 | border: none; 157 | } 158 | 159 | img, 160 | svg { 161 | transition: all 0.3s ease; 162 | 163 | & * { 164 | transition: all 0.3s ease; 165 | } 166 | } 167 | 168 | img { 169 | display: inline-block; 170 | max-width: 100%; 171 | width: auto; 172 | height: auto; 173 | border-style: none; 174 | object-fit: contain; 175 | } 176 | 177 | strong, 178 | b { 179 | font-weight: 700; 180 | color: ${theme.colors.dark}; 181 | } 182 | 183 | table { 184 | width: 100%; 185 | border-collapse: collapse; 186 | 187 | & th, 188 | & td { 189 | text-align: left; 190 | border-bottom: solid 1px ${theme.colors.grayLight}; 191 | padding: 5px 20px 5px 0; 192 | white-space: nowrap; 193 | } 194 | 195 | & th { 196 | font-size: ${theme.sizes.button.size.mobile}; 197 | 198 | ${mq(Breakpoints.lg)} { 199 | font-size: ${theme.sizes.button.size.desktop}; 200 | } 201 | } 202 | 203 | & td { 204 | font-size: ${theme.sizes.text.size.mobile}; 205 | color: ${theme.colors.gray}; 206 | 207 | ${mq(Breakpoints.lg)} { 208 | font-size: ${theme.sizes.text.size.desktop}; 209 | } 210 | 211 | &:first-of-type { 212 | font-weight: 600; 213 | color: ${theme.colors.dark}; 214 | } 215 | } 216 | } 217 | `} 218 | /> 219 | ); 220 | 221 | export { globalStyles }; 222 | --------------------------------------------------------------------------------