diff options
-rw-r--r-- | src/components/project-detail.js | 54 | ||||
-rw-r--r-- | src/components/project.js | 50 | ||||
-rw-r--r-- | src/pages/about.js | 7 | ||||
-rw-r--r-- | src/pages/index.js | 3 | ||||
-rw-r--r-- | src/pages/projects.js | 92 | ||||
-rw-r--r-- | src/pages/work.js | 186 |
6 files changed, 283 insertions, 109 deletions
diff --git a/src/components/project-detail.js b/src/components/project-detail.js new file mode 100644 index 0000000..f84a5c9 --- /dev/null +++ b/src/components/project-detail.js @@ -0,0 +1,54 @@ +import React from 'react' +import { css } from '@emotion/core' + +import { SplitContainer } from './split-container' +import { Image } from './image' +import { margins, breakpoints } from './globals' + +const descContainerStyle = css` + width: 100%; + display: flex; + flex-direction: column; + justify-content: flex-start; + @media (min-width: ${breakpoints[0].breakpoint}px) { + margin: 0 0 0 ${margins.md}px; + flex: 1; + } + & > * { + margin: 0 0 ${margins.md}px 0; + } +` + +const imgContainerStyle = css` + display: flex; + & > *:not(:last-child) { + margin-right: ${margins.sm}px; + } +` + +export const ProjectDetail = ({ listItems, header, images }) => ( + <section + css={css` + width: 100%; + margin-bottom: ${margins.md}px; + `} + > + <SplitContainer> + <div css={descContainerStyle}> + {header ? <h4>{header}</h4> : null} + {listItems ? ( + <ul> + {listItems.map((k, i) => ( + <li key={`detail-item-${i}`}>{k}</li> + ))} + </ul> + ) : null} + </div> + <div css={imgContainerStyle}> + {images + ? images.map((k, i) => <Image key={`image-${i}`} {...k} />) + : null} + </div> + </SplitContainer> + </section> +) diff --git a/src/components/project.js b/src/components/project.js index 9b5bf7e..b827d70 100644 --- a/src/components/project.js +++ b/src/components/project.js @@ -5,13 +5,13 @@ import { FontAwesomeIcon } from '@fortawesome/react-fontawesome' import { faLink } from '@fortawesome/free-solid-svg-icons' import { Tag } from './tag' -import { margins, breakpoints } from './globals' +import { ProjectDetail } from './project-detail' +import { margins } from './globals' const projectHeadingStyle = css` margin: 0 ${margins.sm}px 0 0; ` const projectBriefStyle = css` - margin: 0; font-weight: 300; ` @@ -20,10 +20,6 @@ const projectBlockStyle = css` flex-wrap: wrap; ` -const imgStyle = css` - max-height: 85vw; -` - const linkStyle = css` display: flex; align-content: center; @@ -37,6 +33,9 @@ const linkStyle = css` const projectStyle = css` margin: 0 0 ${margins.lg}px 0; + & > * { + margin: 0 0 ${margins.md}px 0; + } ` const linkIconStyle = css` @@ -63,29 +62,6 @@ const dateStyle = css` ` export const Project = p => { - const marginRight = p.imgUrl ? margins.md : 0 - const descContainerStyle = css` - font-weight: 300; - display: flex; - flex-direction: column; - justify-content: center; - margin: ${margins.md}px 0 0 0; - @media (min-width: ${breakpoints[0].breakpoint}px) { - margin: 0 0 0 ${marginRight}px; - flex: 1; - } - & > * { - margin: 0 0 ${margins.md}px 0; - } - - & img { - max-height: 150px; - align-self: flex-end; - box-shadow: 0 14px 28px rgba(0,0,0,0.25), 0 10px 10px rgba(0,0,0,0.22); - 0 15px 12px rgba(0, 0, 0, 0.22); - margin-bottom: ${margins.md}px; - } - ` return ( <article css={projectStyle}> <div css={projectHeadingContainerStyle}> @@ -107,8 +83,20 @@ export const Project = p => { </div> <h3 css={projectBriefStyle}>{p.brief}</h3> <div css={projectBlockStyle}> - {p.imgUrl ? <img src={p.imgUrl} alt={p.imgAlt} css={imgStyle} /> : null} - {p.desc ? <div css={descContainerStyle}>{p.desc}</div> : null} + {p.desc ? ( + <div + css={css` + margin-bottom: ${margins.md}px; + `} + > + {p.desc} + </div> + ) : null} + {p.projectDetails + ? p.projectDetails.map((k, i) => ( + <ProjectDetail key={`project-detail-${i}`} {...k} /> + )) + : null} </div> </article> ) diff --git a/src/pages/about.js b/src/pages/about.js index daab814..c8f050e 100644 --- a/src/pages/about.js +++ b/src/pages/about.js @@ -9,6 +9,7 @@ import { } from '@fortawesome/free-solid-svg-icons' import Layout from '../components/layout' +import { margins } from '../components/globals' import { AboutEntry } from '../components/about-entry' import { Personal } from '../components/personal' import { SplitContainer } from '../components/split-container' @@ -100,7 +101,11 @@ export default () => ( <Personal {...personalProps} /> <div> {aboutLists.map((entry, i) => ( - <AboutEntry {...entry} key={`about-entry-${i}`} /> + <AboutEntry + {...entry} + headerMargin={`0 0 ${margins.md}px 0`} + key={`about-entry-${i}`} + /> ))} </div> </SplitContainer> diff --git a/src/pages/index.js b/src/pages/index.js index 14e4b4d..26c481c 100644 --- a/src/pages/index.js +++ b/src/pages/index.js @@ -7,7 +7,8 @@ import Layout from '../components/layout' import { Splash } from '../components/splash' const indexData = { - heroText: `Let's make computers work for us`, + heroText: `Hello world 👋`, + heroTagline: `Let's build software for life`, heroBtnTo: '/about', heroBtn: ( <> diff --git a/src/pages/projects.js b/src/pages/projects.js index 8ee306c..0c55834 100644 --- a/src/pages/projects.js +++ b/src/pages/projects.js @@ -16,15 +16,27 @@ export const projects = [ brief: 'A Battlesnake so close to the metal, 6 CVEs have been opened while reading', date: 'Feb 2019 - Present', - desc: 'I tried to make a really fast snake', + desc: ( + <p> + A fast snake where everything is implemented by hand in C to perform a + fast traversal of all possible game states. The implementation is still + unfinished but I hope to enter it in the Battlesnake 2020 competition. + </p> + ), url: '//github.com/nvandoorn/cnaked' }, { name: 'naive', brief: 'A naive implementation of a NoSQL database', date: 'Jan 2019 - Present', - desc: - 'Use this database in prod and you will be on the news for the wrong reasons', + desc: ( + <p> + A small realtime NoSQL database that can be used locally or over a + network. The public interface for this database mimic that of the + Firebase Realtime Database and data is persisted using a static JSON + file. For that reason, I do not suggest using this in production. + </p> + ), url: '//github.com/nvandoorn/naive', showOnCv: true }, @@ -32,8 +44,12 @@ export const projects = [ name: 'Pipefitter', brief: 'Automated audits and monitoring for your ISP', date: 'Nov 2018 - Present', - desc: `My home internet performance is really bad and my ISP never believes me. - Hopefully they will soon. Designed for maximum plug-ability`, + desc: ( + <p> + My home internet performance is consistently below spec and my ISP never + believes me. Hopefully they will soon. Designed for maximum plug-ability + </p> + ), url: '//github.com/nvandoorn/pipefitter', showOnCv: true }, @@ -41,8 +57,12 @@ export const projects = [ name: 'funCtional', brief: 'Functional programming in C with statically allocated memory', date: 'Aug 2018', - desc: `I like functional programming and I like C, so I tried to combine the two. - In reality, a simple for loop is better, but I had fun trying this.`, + desc: ( + <p> + I like functional programming and I like C, so I tried to combine the + two. In reality, a simple for loop is better, but I had fun trying this. + </p> + ), imgUrl: functional, inProd: true, url: '//github.com/nvandoorn/functional' @@ -52,9 +72,13 @@ export const projects = [ brief: 'Non-volatile time series data storage', date: 'Jun 2018 - Present', imgUrl: storageService, - desc: `The Legato Linux framework offers out of the box support for - uploading time series data, but not storing it locally. For this reason, - we created this service to persist data for offline cases.`, + desc: ( + <p> + The Legato Linux framework offers out of the box support for uploading + time series data, but not storing it locally. For this reason, we + created this service to persist data for offline cases. + </p> + ), url: '//github.com/brnkl/legato-storage-service' }, { @@ -63,10 +87,14 @@ export const projects = [ 'Monitor GPS in a separate process to avoid blocking single threaded apps', date: 'April 2018', imgUrl: gpsMonitor, - desc: `Instead of managing and synchronizing a thread to monitor GPS location - on embedded devices, this service asynchronously monitors the GPS position - and allows users to retrieve it using an inter process API - (see more about Legato IPC APIs here).`, + desc: ( + <p> + Instead of managing and synchronizing a thread to monitor GPS location + on embedded devices, this service asynchronously monitors the GPS + position and allows users to retrieve it using an inter process API (see + more about Legato IPC APIs here). + </p> + ), inProd: true, url: '//github.com/brnkl/gps-monitor', showOnCv: true @@ -75,11 +103,16 @@ export const projects = [ name: 'CF3 Config App', brief: 'Automatically configure common settings for CF3 based modules', date: 'April 2018', - desc: `Sierra Wireless offers a range of cellular modules based on a common socket with a - common set of inputs and outputs.A range of commonly used input / output pins and UART - connections must be configured by running an AT command over a serial connection to the - CF3 based modem.Run this app once and the CF3 based module will support the full range of - GPIO pins and UARTs in the Linux userspace.`, + desc: ( + <p> + Sierra Wireless offers a range of cellular modules based on a common + socket with a common set of inputs and outputs.A range of commonly used + input / output pins and UART connections must be configured by running + an AT command over a serial connection to the CF3 based modem.Run this + app once and the CF3 based module will support the full range of GPIO + pins and UARTs in the Linux userspace. + </p> + ), inProd: true, url: '' }, @@ -87,12 +120,17 @@ export const projects = [ name: 'Legato Camera Driver', brief: 'Support for the VC0706 camera on a Legato based project', date: 'Nov 2017 - Dec 2017', - desc: `The VC0706 camera is one of the only low power remote cameras with an open protocol - (serial port based).The seller, Adafruit, supplies open source drivers implemented - in Python and C++ with the purpose of running on Arduino based systems. This means - a dependency on certain Arduino libraries for reading and writing to the serial port. - We re-implemented the C++ driver in C without the dependence on anything - not included in Linux (with the exception of a few Legato specific macros).`, + desc: ( + <p> + The VC0706 camera is one of the only low power remote cameras with an + open protocol (serial port based).The seller, Adafruit, supplies open + source drivers implemented in Python and C++ with the purpose of running + on Arduino based systems. This means a dependency on certain Arduino + libraries for reading and writing to the serial port. We re-implemented + the C++ driver in C without the dependence on anything not included in + Linux (with the exception of a few Legato specific macros). + </p> + ), imgUrl: camera, inProd: true, url: '//github.com/brnkl/VC0706-cam-lib', @@ -113,13 +151,13 @@ export const projects = [ brief: 'A lightweight log viewer and server all in one', date: 'Mar 2017 - Present', desc: ( - <> + <p> slask is designed to make remote systems debugging easy. During my time at Forest Technology Systems (FTS), we worked on a remote weather station based on a single board Linux computer. During the early days, I spent large amounts of time transferring and filtering log files using a mix of <em>scp</em>, <em>grep</em>, and <em>less</em>. - </> + </p> ), imgUrl: slask, url: '//github.com/nvandoorn/slask' diff --git a/src/pages/work.js b/src/pages/work.js index 1f8266c..19cf86c 100644 --- a/src/pages/work.js +++ b/src/pages/work.js @@ -3,47 +3,119 @@ import React from 'react' import Layout from '../components/layout' import { Project } from '../components/project' +import startupOfTheYear from '../images/startup-of-the-year.jpg' +import brnklAppMap from '../images/brnkl-app-map-iphone.png' +import brnklAppAlerts from '../images/brnkl-app-alerts-iphone.png' +import brnklProduct from '../images/brnkl-product.jpg' +import wpModule from '../images/wp-module.png' + export const workHistory = [ { name: 'Lead Software Developer', brief: 'BRNKL by Barnacle Systems', date: 'Sept 2017 - Feb 2019', + projectDetails: [ + { + header: 'Awards', + listItems: [ + <> + <a href="https://sbbcawards.ca/winners/"> Best New Concept</a>, + Small Business BC, Feb 2019 + </>, + <> + <a href="https://www.passagemaker.com/trawler-news/vancouver-boat-show-best-in-show-awards"> + {' '} + Most Innovative (Best In Show) + </a> + , Vancouver International Boat Show, Feb 2019 + </>, + <> + <a href="http://viatecawards.com/2018-recipients/#elementor-tab-title-6044"> + {' '} + Startup of The Year + </a> + , VIATEC, June 2018 + </> + ], + images: [ + { imgUrl: startupOfTheYear, caption: 'VIATEC Startup of The Year' } + ] + }, + { + header: <a href="https://app.brnkl.io"> App</a>, + listItems: [ + 'Implemented with TypeScript, Angular, and RxJS', + 'Deployed on iOS, Android, and the web', + 'Realtime data using RxJS and Firebase Realtime Database', + 'Push alerts implemented over Firebase Cloud Messaging' + ], + images: [ + { + imgUrl: brnklAppMap, + caption: 'BRNKL App Map View', + noShadow: true + }, + { + imgUrl: brnklAppAlerts, + caption: 'BRNKL App Alert View', + noShadow: true + } + ] + }, + { + header: 'Backend', + listItems: [ + 'Written in TypeScript and run on Node', + 'Covered by unit tests and integration tests', + 'Deployed on Google Cloud Pubsub and Firebase Functions', + 'Integrated with cellular network via Sierra Wireless' + ] + }, + { + header: 'Embedded', + listItems: [ + <> + Written in C with the{' '} + <a href="https://legato.io">Legato Framework</a> + </>, + <> + Custom circuit board based on ARM chip with{' '} + <a href="https://www.yoctoproject.org/">Yocto Linux</a> + </>, + 'Custom drivers for hardware peripherals (userspace and kernelspace)', + 'Integration with backend to implement custom business logic', + 'Successful deploys of over the air updates to customers', + <> + Active member of <a href="https://forum.legato.io">Legato</a> and{' '} + <a href="https://forum.mangoh.io">mangOH</a> communities + </> + ], + images: [{ imgUrl: brnklProduct, caption: 'BRNKL embedded device' }] + }, + { + header: 'Production Automation', + listItems: [ + 'Test circuit boards against a suite of hardware tests', + 'Automate installtion of latest firmware release for hardware', + 'Automated delivery of diagnostic messages to factory workers', + 'Automation of device inventory (e.g collecting board serial numbers)' + ], + images: [ + { + imgUrl: wpModule, + caption: 'Sierra Wireless WP85 Module (core of BRNKL)', + noShadow: true + } + ] + } + ], desc: ( - <> - <h4>Awards</h4> - <ul> - <li>Best New Concept, Small Business BC, Feb 2019</li> - <li> - Most Innovative (Best In Show), Vancouver International Boat Show, - Feb 2019 - </li> - <li>Startup of the Year, VIATEC, June 2018</li> - </ul> - <h4>App</h4> - <ul> - <li>Written in TypeScript with Angular</li> - <li>Deployed on iOS, Android, and web</li> - <li>Realtime data from Firebase Realtime Database</li> - <li>Push alerts implemented over Firebase Cloud Messaging</li> - </ul> - <h4>Backend</h4> - <ul> - <li>Written in TypeScript and run on Node</li> - <li>Covered by unit tests and integration tests</li> - <li>Deployed on Google Cloud Pubsub and Firebase Functions</li> - <li>Integrated with cellular network via Sierra Wireless</li> - </ul> - <h4>Embedded</h4> - <ul> - <li>Written in C with the Legato Framework</li> - <li>Custom board based on ARM chip with Linux</li> - <li> - Custom drivers for hardware peripherals (userspace and kernelspace) - </li> - <li>Integration with backend to implement custom business logic</li> - <li>Successful deploys of over the air updates to customers</li> - </ul> - </> + <p> + Barnacle Systems is a self bootstrapped company working on boat + monitoring and security. I worked as the sole implementer of the the + BRNKL app, backend, embedded firmware, and production automation + software (with thanks to many open source authors). + </p> ), url: '//brnkl.io' }, @@ -51,27 +123,43 @@ export const workHistory = [ name: 'Software Developer, Contract', brief: 'BRNKL by Barnacle Systems', date: 'Jul 2017 - Sept 2017', - desc: <></>, - imgUrl: '', + desc: ( + <p> + One of my co-workers from Forest Technology Systems left to found their + own company and approached me to help with the initial version of the + app and backend. + </p> + ), + projectDetails: [ + { + listItems: [ + 'Transform mockups and prototype of app into initial commercial release', + 'Implement initial backend based on prototype implementation', + `Design infrastructure such that it is self managed (i.e "stateless" or "serverless")`, + 'Design and implement local test environment for backend' + ] + } + ], url: '//brnkl.io' }, { name: 'Software Developer, Co-op', brief: 'Forest Technology Systems', date: 'Sept 2016 - April 2017', + projectDetails: [ + { + listItems: [ + 'Implement components of embedded camera product aimed at the fire weather market (FTS RAOS)', + 'Automate builds and installs', + 'Integrate with user facing software as a service product' + ] + } + ], desc: ( - <ul> - <li> - Worked with small cross-functional team of engineers, product - managers, and sales staff - </li> - <li> - Implement components of embedded camera product aimed at the fire - weather market (FTS RAOS) - </li> - <li>Automate builds and installs</li> - <li>Integrate with user facing software as a service product</li> - </ul> + <p> + During my time at Forest Technology Systems, I worked with a small + cross-functional team of engineers, product managers, and sales staff. + </p> ), url: '//ftsinc.com/' } |