diff --git a/config/navigation.yaml b/config/navigation.yaml index 33372b1..ab50c9d 100644 --- a/config/navigation.yaml +++ b/config/navigation.yaml @@ -1,6 +1,6 @@ -- name: "Projects" - link: "/projects" -- name: "Instagram" - link: "/instagram" -- name: "About" - link: "/about" \ No newline at end of file +- name: 'Home' + link: '/projects' +- name: 'Log Contact' + link: '/app/contact' +- name: 'Profile' + link: '/app/profile' diff --git a/firestore.indexes.json b/firestore.indexes.json new file mode 100644 index 0000000..415027e --- /dev/null +++ b/firestore.indexes.json @@ -0,0 +1,4 @@ +{ + "indexes": [], + "fieldOverrides": [] +} diff --git a/firestore.rules b/firestore.rules new file mode 100644 index 0000000..c38e3ae --- /dev/null +++ b/firestore.rules @@ -0,0 +1,8 @@ +rules_version = '2'; +service cloud.firestore { + match /databases/{database}/documents { + match /{document=**} { + allow read, write: if false; + } + } +} \ No newline at end of file diff --git a/functions/.gitignore b/functions/.gitignore new file mode 100644 index 0000000..7fbb8b4 --- /dev/null +++ b/functions/.gitignore @@ -0,0 +1,8 @@ +## Compiled JavaScript files +**/*.js +**/*.js.map + +# Typescript v1 declaration files +typings/ + +node_modules/ \ No newline at end of file diff --git a/functions/package.json b/functions/package.json new file mode 100644 index 0000000..7f381da --- /dev/null +++ b/functions/package.json @@ -0,0 +1,26 @@ +{ + "name": "functions", + "scripts": { + "lint": "tslint --project tsconfig.json", + "build": "tsc", + "serve": "npm run build && firebase emulators:start --only functions", + "shell": "npm run build && firebase functions:shell", + "start": "npm run shell", + "deploy": "firebase deploy --only functions", + "logs": "firebase functions:log" + }, + "engines": { + "node": "8" + }, + "main": "lib/index.js", + "dependencies": { + "firebase-admin": "^8.6.0", + "firebase-functions": "^3.3.0" + }, + "devDependencies": { + "tslint": "^5.12.0", + "typescript": "^3.2.2", + "firebase-functions-test": "^0.1.6" + }, + "private": true +} diff --git a/functions/src/index.ts b/functions/src/index.ts new file mode 100644 index 0000000..1f3fc67 --- /dev/null +++ b/functions/src/index.ts @@ -0,0 +1,8 @@ +import * as functions from 'firebase-functions'; + +// // Start writing Firebase Functions +// // https://firebase.google.com/docs/functions/typescript +// +// export const helloWorld = functions.https.onRequest((request, response) => { +// response.send("Hello from Firebase!"); +// }); diff --git a/functions/tsconfig.json b/functions/tsconfig.json new file mode 100644 index 0000000..7ce05d0 --- /dev/null +++ b/functions/tsconfig.json @@ -0,0 +1,15 @@ +{ + "compilerOptions": { + "module": "commonjs", + "noImplicitReturns": true, + "noUnusedLocals": true, + "outDir": "lib", + "sourceMap": true, + "strict": true, + "target": "es2017" + }, + "compileOnSave": true, + "include": [ + "src" + ] +} diff --git a/functions/tslint.json b/functions/tslint.json new file mode 100644 index 0000000..98b2bfd --- /dev/null +++ b/functions/tslint.json @@ -0,0 +1,115 @@ +{ + "rules": { + // -- Strict errors -- + // These lint rules are likely always a good idea. + + // Force function overloads to be declared together. This ensures readers understand APIs. + "adjacent-overload-signatures": true, + + // Do not allow the subtle/obscure comma operator. + "ban-comma-operator": true, + + // Do not allow internal modules or namespaces . These are deprecated in favor of ES6 modules. + "no-namespace": true, + + // Do not allow parameters to be reassigned. To avoid bugs, developers should instead assign new values to new vars. + "no-parameter-reassignment": true, + + // Force the use of ES6-style imports instead of /// imports. + "no-reference": true, + + // Do not allow type assertions that do nothing. This is a big warning that the developer may not understand the + // code currently being edited (they may be incorrectly handling a different type case that does not exist). + "no-unnecessary-type-assertion": true, + + // Disallow nonsensical label usage. + "label-position": true, + + // Disallows the (often typo) syntax if (var1 = var2). Replace with if (var2) { var1 = var2 }. + "no-conditional-assignment": true, + + // Disallows constructors for primitive types (e.g. new Number('123'), though Number('123') is still allowed). + "no-construct": true, + + // Do not allow super() to be called twice in a constructor. + "no-duplicate-super": true, + + // Do not allow the same case to appear more than once in a switch block. + "no-duplicate-switch-case": true, + + // Do not allow a variable to be declared more than once in the same block. Consider function parameters in this + // rule. + "no-duplicate-variable": [true, "check-parameters"], + + // Disallows a variable definition in an inner scope from shadowing a variable in an outer scope. Developers should + // instead use a separate variable name. + "no-shadowed-variable": true, + + // Empty blocks are almost never needed. Allow the one general exception: empty catch blocks. + "no-empty": [true, "allow-empty-catch"], + + // Functions must either be handled directly (e.g. with a catch() handler) or returned to another function. + // This is a major source of errors in Cloud Functions and the team strongly recommends leaving this rule on. + "no-floating-promises": true, + + // Do not allow any imports for modules that are not in package.json. These will almost certainly fail when + // deployed. + "no-implicit-dependencies": true, + + // The 'this' keyword can only be used inside of classes. + "no-invalid-this": true, + + // Do not allow strings to be thrown because they will not include stack traces. Throw Errors instead. + "no-string-throw": true, + + // Disallow control flow statements, such as return, continue, break, and throw in finally blocks. + "no-unsafe-finally": true, + + // Expressions must always return a value. Avoids common errors like const myValue = functionReturningVoid(); + "no-void-expression": [true, "ignore-arrow-function-shorthand"], + + // Disallow duplicate imports in the same file. + "no-duplicate-imports": true, + + + // -- Strong Warnings -- + // These rules should almost never be needed, but may be included due to legacy code. + // They are left as a warning to avoid frustration with blocked deploys when the developer + // understand the warning and wants to deploy anyway. + + // Warn when an empty interface is defined. These are generally not useful. + "no-empty-interface": {"severity": "warning"}, + + // Warn when an import will have side effects. + "no-import-side-effect": {"severity": "warning"}, + + // Warn when variables are defined with var. Var has subtle meaning that can lead to bugs. Strongly prefer const for + // most values and let for values that will change. + "no-var-keyword": {"severity": "warning"}, + + // Prefer === and !== over == and !=. The latter operators support overloads that are often accidental. + "triple-equals": {"severity": "warning"}, + + // Warn when using deprecated APIs. + "deprecation": {"severity": "warning"}, + + // -- Light Warnings -- + // These rules are intended to help developers use better style. Simpler code has fewer bugs. These would be "info" + // if TSLint supported such a level. + + // prefer for( ... of ... ) to an index loop when the index is only used to fetch an object from an array. + // (Even better: check out utils like .map if transforming an array!) + "prefer-for-of": {"severity": "warning"}, + + // Warns if function overloads could be unified into a single function with optional or rest parameters. + "unified-signatures": {"severity": "warning"}, + + // Prefer const for values that will not change. This better documents code. + "prefer-const": {"severity": "warning"}, + + // Multi-line object literals and function calls should have a trailing comma. This helps avoid merge conflicts. + "trailing-comma": {"severity": "warning"} + }, + + "defaultSeverity": "error" +} diff --git a/src/components/PrimaryNav/PrimaryNav.tsx b/src/components/PrimaryNav/PrimaryNav.tsx new file mode 100644 index 0000000..2b0585d --- /dev/null +++ b/src/components/PrimaryNav/PrimaryNav.tsx @@ -0,0 +1,62 @@ +import * as React from 'react'; +import { graphql, useStaticQuery, Link } from 'gatsby'; + +const query = graphql` + query PrimaryNav { + navigation: allNavigationYaml { + nodes { + name + link + } + } + } +`; + +interface QueryResult { + navigation: { + nodes: { + name: string; + link: string; + }[]; + }; +} + +const isPartiallyActive = ({ + isPartiallyCurrent +}: { + isPartiallyCurrent: boolean; +}) => + isPartiallyCurrent + ? { className: 'navlink-active navlink' } + : { className: 'navlink' }; + +const PartialNavLink = ({ + children, + to, + ...rest +}: { + children: React.ReactNode; + to: string; +}) => ( + + {children} + +); + +const PrimaryNav: React.FC = () => { + const { + navigation: { nodes } + } = useStaticQuery(query); + + return ( + + ); +}; + +export default PrimaryNav; diff --git a/src/components/PrimaryNav/index.ts b/src/components/PrimaryNav/index.ts new file mode 100644 index 0000000..fe493d4 --- /dev/null +++ b/src/components/PrimaryNav/index.ts @@ -0,0 +1 @@ +export { default } from './PrimaryNav'; diff --git a/src/components/layout.tsx b/src/components/layout.tsx index 184efdd..b7fab2f 100644 --- a/src/components/layout.tsx +++ b/src/components/layout.tsx @@ -1,12 +1,13 @@ -import React from 'react' -import styled, { createGlobalStyle, ThemeProvider } from 'styled-components' -import { graphql, Link, useStaticQuery } from 'gatsby' -import { readableColor } from 'polished' -import 'typeface-work-sans' -import { Box, Flex } from '../elements' -import theme from '../../config/theme' -import reset from '../styles/reset' -import Logo from './logo' +import React from 'react'; +import styled, { createGlobalStyle, ThemeProvider } from 'styled-components'; +import { Link } from 'gatsby'; +import { readableColor } from 'polished'; +import 'typeface-work-sans'; +import { Box, Flex } from '../elements'; +import theme from '../../config/theme'; +import reset from '../styles/reset'; +import Logo from './logo'; +import PrimaryNav from './PrimaryNav'; const GlobalStyles = createGlobalStyle` *::before, @@ -88,16 +89,7 @@ const GlobalStyles = createGlobalStyle` } ${reset} -` - -const isPartiallyActive = ({ isPartiallyCurrent }: { isPartiallyCurrent: boolean }) => - isPartiallyCurrent ? { className: 'navlink-active navlink' } : { className: 'navlink' } - -const PartialNavLink = ({ children, to, ...rest }: { children: React.ReactNode; to: string }) => ( - - {children} - -) +`; const Wrapper = styled.div` display: grid; @@ -109,7 +101,7 @@ const Wrapper = styled.div` @media (max-width: ${props => props.theme.breakpoints[2]}) { grid-template-columns: 1fr; } -` +`; const SideBarInner = styled(Box)<{ bg: string }>` position: fixed; @@ -134,7 +126,7 @@ const SideBarInner = styled(Box)<{ bg: string }>` svg { fill: ${props => readableColor(`${props.bg}`)}; } -` +`; const Nav = styled(Flex)<{ color: string }>` a { @@ -163,13 +155,13 @@ const Nav = styled(Flex)<{ color: string }>` margin-left: ${props => props.theme.space[2]}; } } -` +`; const Main = styled.main` @media (min-width: calc(${props => props.theme.breakpoints[2]} + 1px)) { grid-column-start: 2; } -` +`; const Footer = styled.footer<{ color: string }>` position: fixed; @@ -178,7 +170,8 @@ const Footer = styled.footer<{ color: string }>` background: ${props => props.color}; - color: ${props => readableColor(`${props.color}`, `${props.theme.colors.grey}`, '#c3c3c3')}; + color: ${props => + readableColor(`${props.color}`, `${props.theme.colors.grey}`, '#c3c3c3')}; a { color: ${props => readableColor(`${props.color}`)}; @@ -196,26 +189,15 @@ const Footer = styled.footer<{ color: string }>` position: relative; width: 100%; } -` +`; -type LayoutProps = { children: React.ReactNode } & typeof defaultProps +type LayoutProps = { children: React.ReactNode } & typeof defaultProps; const defaultProps = { - color: 'white', -} - -interface QueryResult { - navigation: { - nodes: { - name: string - link: string - }[] - } -} + color: 'white' +}; const Layout = ({ children, color }: LayoutProps) => { - const data: QueryResult = useStaticQuery(query) - return ( <> @@ -241,38 +223,27 @@ const Layout = ({ children, color }: LayoutProps) => { flexDirection={['row', 'row', 'row', 'column']} alignItems="flex-start" > - {data.navigation.nodes.map(item => ( - - {item.name} - - ))} +
{children}
- ) -} + ); +}; -export default Layout +export default Layout; -Layout.defaultProps = defaultProps - -const query = graphql` - query Layout { - navigation: allNavigationYaml { - nodes { - name - link - } - } - } -` +Layout.defaultProps = defaultProps; diff --git a/src/pages/app.tsx b/src/pages/app.tsx index 73f9591..ec97475 100644 --- a/src/pages/app.tsx +++ b/src/pages/app.tsx @@ -3,12 +3,14 @@ import { Router } from '@reach/router'; import Layout from '../components/layout'; import PrivateRoute from '../components/PrivateRoute'; import ContactView from '../views/contact'; +import ProfileView from '../views/profile'; const App = () => { return ( + ); diff --git a/src/views/profile/index.ts b/src/views/profile/index.ts new file mode 100644 index 0000000..52811c9 --- /dev/null +++ b/src/views/profile/index.ts @@ -0,0 +1 @@ +export { default } from './profile'; diff --git a/src/views/profile/profile.tsx b/src/views/profile/profile.tsx new file mode 100644 index 0000000..d41a1d1 --- /dev/null +++ b/src/views/profile/profile.tsx @@ -0,0 +1,7 @@ +import * as React from 'react'; + +const ProfileView = () => { + return
Profile View
; +}; + +export default ProfileView;