🎉 Initial Commit!
This commit is contained in:
commit
0eee4e6a07
15
.editorconfig
Normal file
15
.editorconfig
Normal file
|
@ -0,0 +1,15 @@
|
||||||
|
# https://editorconfig.org
|
||||||
|
root = true
|
||||||
|
|
||||||
|
[*]
|
||||||
|
charset = utf-8
|
||||||
|
end_of_line = lf
|
||||||
|
|
||||||
|
[*{.ts,.js}]
|
||||||
|
indent_style = space
|
||||||
|
indent_size = 2
|
||||||
|
trim_trailing_whitespace = true
|
||||||
|
insert_final_newline = true
|
||||||
|
|
||||||
|
[*.md]
|
||||||
|
trim_trailing_whitespace = false
|
25
.eslintrc.js
Normal file
25
.eslintrc.js
Normal file
|
@ -0,0 +1,25 @@
|
||||||
|
module.exports = {
|
||||||
|
"env": {
|
||||||
|
"browser": true,
|
||||||
|
"es2021": true
|
||||||
|
},
|
||||||
|
"extends": [
|
||||||
|
"plugin:react/recommended",
|
||||||
|
"airbnb"
|
||||||
|
],
|
||||||
|
"parser": "@typescript-eslint/parser",
|
||||||
|
"parserOptions": {
|
||||||
|
"ecmaFeatures": {
|
||||||
|
"jsx": true
|
||||||
|
},
|
||||||
|
"ecmaVersion": 12,
|
||||||
|
"sourceType": "module"
|
||||||
|
},
|
||||||
|
"plugins": [
|
||||||
|
"react",
|
||||||
|
"@typescript-eslint"
|
||||||
|
],
|
||||||
|
"rules": {
|
||||||
|
"indent": ["error", 2]
|
||||||
|
}
|
||||||
|
};
|
34
.gitignore
vendored
Normal file
34
.gitignore
vendored
Normal file
|
@ -0,0 +1,34 @@
|
||||||
|
# See https://help.github.com/articles/ignoring-files/ for more about ignoring files.
|
||||||
|
|
||||||
|
# dependencies
|
||||||
|
/node_modules
|
||||||
|
/.pnp
|
||||||
|
.pnp.js
|
||||||
|
|
||||||
|
# testing
|
||||||
|
/coverage
|
||||||
|
|
||||||
|
# next.js
|
||||||
|
/.next/
|
||||||
|
/out/
|
||||||
|
|
||||||
|
# production
|
||||||
|
/build
|
||||||
|
|
||||||
|
# misc
|
||||||
|
.DS_Store
|
||||||
|
*.pem
|
||||||
|
|
||||||
|
# debug
|
||||||
|
npm-debug.log*
|
||||||
|
yarn-debug.log*
|
||||||
|
yarn-error.log*
|
||||||
|
|
||||||
|
# local env files
|
||||||
|
.env.local
|
||||||
|
.env.development.local
|
||||||
|
.env.test.local
|
||||||
|
.env.production.local
|
||||||
|
|
||||||
|
# vercel
|
||||||
|
.vercel
|
41
README.md
Normal file
41
README.md
Normal file
|
@ -0,0 +1,41 @@
|
||||||
|
# TypeScript Next.js example
|
||||||
|
|
||||||
|
This is a really simple project that shows the usage of Next.js with TypeScript.
|
||||||
|
|
||||||
|
## Deploy your own
|
||||||
|
|
||||||
|
Deploy the example using [Vercel](https://vercel.com?utm_source=github&utm_medium=readme&utm_campaign=next-example):
|
||||||
|
|
||||||
|
[![Deploy with Vercel](https://vercel.com/button)](https://vercel.com/new/git/external?repository-url=https://github.com/vercel/next.js/tree/canary/examples/with-typescript&project-name=with-typescript&repository-name=with-typescript)
|
||||||
|
|
||||||
|
## How to use it?
|
||||||
|
|
||||||
|
Execute [`create-next-app`](https://github.com/vercel/next.js/tree/canary/packages/create-next-app) with [npm](https://docs.npmjs.com/cli/init) or [Yarn](https://yarnpkg.com/lang/en/docs/cli/create/) to bootstrap the example:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
npx create-next-app --example with-typescript with-typescript-app
|
||||||
|
# or
|
||||||
|
yarn create next-app --example with-typescript with-typescript-app
|
||||||
|
```
|
||||||
|
|
||||||
|
Deploy it to the cloud with [Vercel](https://vercel.com/new?utm_source=github&utm_medium=readme&utm_campaign=next-example) ([Documentation](https://nextjs.org/docs/deployment)).
|
||||||
|
|
||||||
|
## Notes
|
||||||
|
|
||||||
|
This example shows how to integrate the TypeScript type system into Next.js. Since TypeScript is supported out of the box with Next.js, all we have to do is to install TypeScript.
|
||||||
|
|
||||||
|
```
|
||||||
|
npm install --save-dev typescript
|
||||||
|
```
|
||||||
|
|
||||||
|
To enable TypeScript's features, we install the type declarations for React and Node.
|
||||||
|
|
||||||
|
```
|
||||||
|
npm install --save-dev @types/react @types/react-dom @types/node
|
||||||
|
```
|
||||||
|
|
||||||
|
When we run `next dev` the next time, Next.js will start looking for any `.ts` or `.tsx` files in our project and builds it. It even automatically creates a `tsconfig.json` file for our project with the recommended settings.
|
||||||
|
|
||||||
|
Next.js has built-in TypeScript declarations, so we'll get autocompletion for Next.js' modules straight away.
|
||||||
|
|
||||||
|
A `type-check` script is also added to `package.json`, which runs TypeScript's `tsc` CLI in `noEmit` mode to run type-checking separately. You can then include this, for example, in your `test` scripts.
|
30
components/Images/Logo.tsx
Normal file
30
components/Images/Logo.tsx
Normal file
|
@ -0,0 +1,30 @@
|
||||||
|
const Logo = () => (
|
||||||
|
<svg
|
||||||
|
width="100%"
|
||||||
|
height="100%"
|
||||||
|
viewBox="0 0 1080 1080"
|
||||||
|
version="1.1"
|
||||||
|
xmlns="http://www.w3.org/2000/svg"
|
||||||
|
xmlnsXlink="http://www.w3.org/1999/xlink"
|
||||||
|
xmlSpace="preserve"
|
||||||
|
fillRule='evenodd'
|
||||||
|
clipRule='evenodd'
|
||||||
|
strokeLinejoin='round'
|
||||||
|
strokeMiterlimit='2'
|
||||||
|
>
|
||||||
|
<g transform="matrix(1.87667,0,0,1.87667,-211.69,-370.379)">
|
||||||
|
<path d="M330.006,585.343L506.715,408.388C513.207,401.887 513.2,391.339 506.699,384.847C500.198,378.355 489.65,378.363 483.158,384.863L306.448,561.819C299.956,568.32 299.964,578.868 306.465,585.36C312.965,591.852 323.514,591.844 330.006,585.343Z" fill="white" />
|
||||||
|
</g>
|
||||||
|
<g transform="matrix(1.87667,0,0,1.87667,-45.877,-370.379)">
|
||||||
|
<path d="M330.006,585.343L506.715,408.388C513.207,401.887 513.2,391.339 506.699,384.847C500.198,378.355 489.65,378.363 483.158,384.863L306.448,561.819C299.956,568.32 299.964,578.868 306.465,585.36C312.965,591.852 323.514,591.844 330.006,585.343Z" fill="white" />
|
||||||
|
</g>
|
||||||
|
<g transform="matrix(1.87667,0,0,1.87667,119.936,-370.379)">
|
||||||
|
<path d="M330.006,585.343L506.715,408.388C513.207,401.887 513.2,391.339 506.699,384.847C500.198,378.355 489.65,378.363 483.158,384.863L306.448,561.819C299.956,568.32 299.964,578.868 306.465,585.36C312.965,591.852 323.514,591.844 330.006,585.343Z" fill="white" />
|
||||||
|
</g>
|
||||||
|
<g transform="matrix(1.87667,0,0,1.87667,-473.399,-473.402)">
|
||||||
|
<path d="M362.424,611.832L534.257,439.76C540.749,433.259 551.297,433.252 557.798,439.744C564.299,446.235 564.306,456.784 557.815,463.285L381.105,640.24C379.514,641.833 377.679,643.037 375.72,643.85L375.686,643.864C373.726,644.676 371.578,645.124 369.326,645.124L268.899,645.124C259.712,645.124 252.253,637.665 252.253,628.478C252.253,619.29 259.712,611.832 268.899,611.832L362.424,611.832Z" fill="white" />
|
||||||
|
</g>
|
||||||
|
</svg>
|
||||||
|
)
|
||||||
|
|
||||||
|
export default Logo;
|
70
components/Navbar.tsx
Normal file
70
components/Navbar.tsx
Normal file
|
@ -0,0 +1,70 @@
|
||||||
|
import Link from "next/link";
|
||||||
|
import { Dispatch, SetStateAction, useEffect, useState } from "react";
|
||||||
|
import Logo from './Images/Logo';
|
||||||
|
|
||||||
|
const Navbar = ({ links }: {
|
||||||
|
links: {
|
||||||
|
label: string;
|
||||||
|
href: string;
|
||||||
|
}[]
|
||||||
|
}) => {
|
||||||
|
const [collapsed, setCollapsed] = useState(false);
|
||||||
|
|
||||||
|
const [atTop, setAtTop] = useState<boolean>()
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
if (window.scrollY === 0) {
|
||||||
|
setAtTop(true)
|
||||||
|
} else {
|
||||||
|
setAtTop(false)
|
||||||
|
}
|
||||||
|
window.addEventListener("scroll", () => {
|
||||||
|
if (window.scrollY === 0) {
|
||||||
|
setAtTop(true)
|
||||||
|
} else {
|
||||||
|
setAtTop(false)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
|
return (
|
||||||
|
<nav className={`fixed w-full flex flex-wrap items-center justify-between px-2 py-6 navbar-expand-lg bg-gray-800 ${atTop ? '' : 'shadow-md'}`}>
|
||||||
|
<div className="container px-4 mx-auto flex flex-wrap items-center justify-between">
|
||||||
|
<div className="w-full relative flex justify-between md:w-auto px-4 md:static md:block md:justify-start items-center">
|
||||||
|
<div className="text-sm font-bold leading-relaxed inline-block mr-4 py-2 whitespace-no-wrap text-white">
|
||||||
|
<Link href="/" aria-label="Stryx Logo">
|
||||||
|
<h1 className="text-white font-extrabold text-2xl">Jack Merrill</h1>
|
||||||
|
</Link>
|
||||||
|
</div>
|
||||||
|
<button className="md:hidden text-gray-500 w-10 h-10 relative focus:outline-none" onClick={() => setCollapsed(!collapsed)}>
|
||||||
|
<span className="sr-only">Open menu</span>
|
||||||
|
<div className="block w-5 absolute left-1/2 top-1/2 transform -translate-x-1/2 -translate-y-1/2">
|
||||||
|
<span aria-hidden="true" className={`block absolute h-0.5 w-5 bg-current transform transition duration-500 ease-in-out ${ !collapsed ? 'rotate-45' : '-translate-y-1.5' }`} />
|
||||||
|
<span aria-hidden="true" className={`block absolute h-0.5 w-5 bg-current transform transition duration-500 ease-in-out ${ !collapsed && 'opacity-0'}`} ></span>
|
||||||
|
<span aria-hidden="true" className={`block absolute h-0.5 w-5 bg-current transform transition duration-500 ease-in-out ${ !collapsed ? '-rotate-45' : 'translate-y-1.5' }`} ></span>
|
||||||
|
</div>
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
<div className={collapsed ? 'md:flex flex-grow items-center hidden' : 'md:flex flex-grow items-center'} id="navbar">
|
||||||
|
<ul className="flex flex-col md:flex-row list-none ml-auto items-center">
|
||||||
|
{links.map(({ label, href }) => (
|
||||||
|
<li className="nav-item">
|
||||||
|
<div className="px-3 py-2 flex items-center leading-snug text-white">
|
||||||
|
<Link href={href} passHref>
|
||||||
|
<a
|
||||||
|
className="font-bold text-gray-200 hover:underline"
|
||||||
|
>
|
||||||
|
{label}
|
||||||
|
</a>
|
||||||
|
</Link>
|
||||||
|
</div>
|
||||||
|
</li>
|
||||||
|
))}
|
||||||
|
</ul>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</nav>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
export default Navbar;
|
10
interfaces/index.ts
Normal file
10
interfaces/index.ts
Normal file
|
@ -0,0 +1,10 @@
|
||||||
|
// You can include shared interfaces/types in a separate file
|
||||||
|
// and then use them in any component by importing them. For
|
||||||
|
// example, to import the interface below do:
|
||||||
|
//
|
||||||
|
// import { User } from 'path/to/interfaces';
|
||||||
|
|
||||||
|
export type User = {
|
||||||
|
id: number
|
||||||
|
name: string
|
||||||
|
}
|
2
next-env.d.ts
vendored
Normal file
2
next-env.d.ts
vendored
Normal file
|
@ -0,0 +1,2 @@
|
||||||
|
/// <reference types="next" />
|
||||||
|
/// <reference types="next/types/global" />
|
5
next.config.js
Normal file
5
next.config.js
Normal file
|
@ -0,0 +1,5 @@
|
||||||
|
module.exports = {
|
||||||
|
future: {
|
||||||
|
webpack5: true,
|
||||||
|
},
|
||||||
|
}
|
26
package.json
Normal file
26
package.json
Normal file
|
@ -0,0 +1,26 @@
|
||||||
|
{
|
||||||
|
"name": "with-typescript",
|
||||||
|
"version": "1.0.0",
|
||||||
|
"scripts": {
|
||||||
|
"dev": "next",
|
||||||
|
"build": "next build",
|
||||||
|
"start": "next start",
|
||||||
|
"type-check": "tsc"
|
||||||
|
},
|
||||||
|
"dependencies": {
|
||||||
|
"next": "latest",
|
||||||
|
"react": "^17.0.1",
|
||||||
|
"react-dom": "^17.0.1"
|
||||||
|
},
|
||||||
|
"devDependencies": {
|
||||||
|
"@fullhuman/postcss-purgecss": "^4.0.3",
|
||||||
|
"@types/node": "^12.12.21",
|
||||||
|
"@types/react": "^17.0.2",
|
||||||
|
"@types/react-dom": "^17.0.1",
|
||||||
|
"autoprefixer": "^10.2.5",
|
||||||
|
"postcss-preset-env": "^6.7.0",
|
||||||
|
"tailwindcss": "^2.0.4",
|
||||||
|
"typescript": "4.0"
|
||||||
|
},
|
||||||
|
"license": "MIT"
|
||||||
|
}
|
10
pages/_app.tsx
Normal file
10
pages/_app.tsx
Normal file
|
@ -0,0 +1,10 @@
|
||||||
|
import React from 'react'
|
||||||
|
import { AppProps } from 'next/app'
|
||||||
|
|
||||||
|
import 'tailwindcss/tailwind.css'
|
||||||
|
|
||||||
|
function MyApp({ Component, pageProps }: AppProps) {
|
||||||
|
return <Component {...pageProps} />
|
||||||
|
}
|
||||||
|
|
||||||
|
export default MyApp
|
23
pages/_document.tsx
Normal file
23
pages/_document.tsx
Normal file
|
@ -0,0 +1,23 @@
|
||||||
|
import Document, { DocumentContext, Head, Html, Main, NextScript } from 'next/document'
|
||||||
|
|
||||||
|
class MyDocument extends Document {
|
||||||
|
static async getInitialProps(ctx: DocumentContext) {
|
||||||
|
const initialProps = await Document.getInitialProps(ctx)
|
||||||
|
|
||||||
|
return initialProps
|
||||||
|
}
|
||||||
|
|
||||||
|
render() {
|
||||||
|
return (
|
||||||
|
<Html>
|
||||||
|
<Head />
|
||||||
|
<body>
|
||||||
|
<Main />
|
||||||
|
<NextScript />
|
||||||
|
</body>
|
||||||
|
</Html>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export default MyDocument
|
50
pages/index.tsx
Normal file
50
pages/index.tsx
Normal file
|
@ -0,0 +1,50 @@
|
||||||
|
import Link from 'next/link'
|
||||||
|
import Navbar from '../components/Navbar'
|
||||||
|
|
||||||
|
function GetTimeString(): string {
|
||||||
|
const hours = new Date().getHours()
|
||||||
|
|
||||||
|
if (hours < 12) {
|
||||||
|
return 'Morning'
|
||||||
|
} else if (hours >= 12 && hours <= 17) {
|
||||||
|
return 'Afternoon'
|
||||||
|
} else if (hours >= 17 && hours <= 24) {
|
||||||
|
return 'Evening'
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const IndexPage = () => (
|
||||||
|
<div id='app'>
|
||||||
|
<main className="bg-gray-800 w-screen h-full min-h-screen">
|
||||||
|
<Navbar links={[
|
||||||
|
{ label: 'Home', href: '/' },
|
||||||
|
{ label: 'Portfolio', href: '/portfolio' },
|
||||||
|
{ label: 'Projects', href: '/projects' },
|
||||||
|
]} />
|
||||||
|
|
||||||
|
<header className="flex flex-wrap flex-col overflow-hidden space-y-2 px-36 items-center justify-center h-screen w-screen">
|
||||||
|
<div className="my-3 px-3 w-full text-center">
|
||||||
|
<h1 className="text-white font-extrabold md:text-6xl text-3xl">Good <span className="text-blue-500">{GetTimeString()}</span>! I'm <span className="text-purple-400">Jack Merrill</span>.</h1>
|
||||||
|
</div>
|
||||||
|
<div className="my-3 px-3 w-full text-center">
|
||||||
|
<h2 className="text-white font-bold md:text-4xl text-2xl">A Graphic and UI/UX Designer and Fullstack Developer from Chicago.</h2>
|
||||||
|
</div>
|
||||||
|
<div className="inline-flex items-center justify-center content-center space-x-4 my-3 px-3 w-full text-center">
|
||||||
|
<Link href="/portfolio">
|
||||||
|
<a className="bg-gradient-to-r from-green-400 to-blue-500 px-4 py-2 rounded-xl font-bold text-white">
|
||||||
|
See my Work
|
||||||
|
</a>
|
||||||
|
</Link>
|
||||||
|
<span className="text-sm font-light text-gray-400">or</span>
|
||||||
|
<Link href="mailto:me@jackmerrill.com">
|
||||||
|
<a className="bg-gradient-to-r from-green-400 to-blue-500 px-4 py-2 rounded-xl font-bold text-white">
|
||||||
|
Contact Me
|
||||||
|
</a>
|
||||||
|
</Link>
|
||||||
|
</div>
|
||||||
|
</header>
|
||||||
|
</main>
|
||||||
|
</div>
|
||||||
|
)
|
||||||
|
|
||||||
|
export default IndexPage
|
18
postcss.config.js
Normal file
18
postcss.config.js
Normal file
|
@ -0,0 +1,18 @@
|
||||||
|
module.exports = {
|
||||||
|
plugins: [
|
||||||
|
'tailwindcss',
|
||||||
|
process.env.NODE_ENV === 'production'
|
||||||
|
? [
|
||||||
|
'@fullhuman/postcss-purgecss',
|
||||||
|
{
|
||||||
|
content: [
|
||||||
|
'./pages/**/*.{js,jsx,ts,tsx}',
|
||||||
|
'./components/**/*.{js,jsx,ts,tsx}',
|
||||||
|
],
|
||||||
|
defaultExtractor: (content) => content.match(/[\w-/:]+(?<!:)/g) || [],
|
||||||
|
},
|
||||||
|
]
|
||||||
|
: undefined,
|
||||||
|
'postcss-preset-env',
|
||||||
|
],
|
||||||
|
};
|
11
tailwind.config.js
Normal file
11
tailwind.config.js
Normal file
|
@ -0,0 +1,11 @@
|
||||||
|
module.exports = {
|
||||||
|
purge: ['./pages/**/*.{js,ts,jsx,tsx}', './components/**/*.{js,ts,jsx,tsx}'],
|
||||||
|
darkMode: 'media', // or 'media' or 'class'
|
||||||
|
theme: {
|
||||||
|
extend: {},
|
||||||
|
},
|
||||||
|
variants: {
|
||||||
|
extend: {},
|
||||||
|
},
|
||||||
|
plugins: [],
|
||||||
|
}
|
23
tsconfig.json
Normal file
23
tsconfig.json
Normal file
|
@ -0,0 +1,23 @@
|
||||||
|
{
|
||||||
|
"compilerOptions": {
|
||||||
|
"allowJs": true,
|
||||||
|
"alwaysStrict": true,
|
||||||
|
"esModuleInterop": true,
|
||||||
|
"forceConsistentCasingInFileNames": true,
|
||||||
|
"isolatedModules": true,
|
||||||
|
"jsx": "preserve",
|
||||||
|
"lib": ["dom", "es2017"],
|
||||||
|
"module": "esnext",
|
||||||
|
"moduleResolution": "node",
|
||||||
|
"noEmit": true,
|
||||||
|
"noFallthroughCasesInSwitch": true,
|
||||||
|
"noUnusedLocals": true,
|
||||||
|
"noUnusedParameters": true,
|
||||||
|
"resolveJsonModule": true,
|
||||||
|
"skipLibCheck": true,
|
||||||
|
"strict": true,
|
||||||
|
"target": "esnext"
|
||||||
|
},
|
||||||
|
"exclude": ["node_modules"],
|
||||||
|
"include": ["**/*.ts", "**/*.tsx"]
|
||||||
|
}
|
9
utils/sample-data.ts
Normal file
9
utils/sample-data.ts
Normal file
|
@ -0,0 +1,9 @@
|
||||||
|
import { User } from '../interfaces'
|
||||||
|
|
||||||
|
/** Dummy user data. */
|
||||||
|
export const sampleUserData: User[] = [
|
||||||
|
{ id: 101, name: 'Alice' },
|
||||||
|
{ id: 102, name: 'Bob' },
|
||||||
|
{ id: 103, name: 'Caroline' },
|
||||||
|
{ id: 104, name: 'Dave' },
|
||||||
|
]
|
Loading…
Reference in New Issue
Block a user