Commit 309e99e4 authored by Tad Lispy's avatar Tad Lispy

Recreate the site using Pug, use Make and Parcel to build it, setup CI

Also self host Lato font. There is a little issue with using @require / 
@import directive in stylus file: the font files are not copied to dist/ 
by Parcel. Workaround is to link the stylesheet directly from index.pug.
parent 6dde0b79
Pipeline #54137265 failed with stage
in 1 minute and 34 seconds
......@@ -6,3 +6,5 @@ npm-debug.log
wiki/
config.cson
.DS_Store
dist/
.cache/
image: node:11
dist:
stage: build
script:
- make
artifacts:
name: "$CI_COMMIT_REF_SLUG"
expire_in: 1 week
paths:
- dist/
pages:
stage: deploy
script:
- mv dist/ public/
artifacts:
paths:
- public/
only:
- master
entries := src/index.pug
.PHONY: all
all: .installed dist
.PHONY: install
install:
@rm -rf .installed
@make .installed
.installed: package.json package-lock.json
@echo "Dependencies files are newer than .installed; (re)installing."
@npm clean-install
@echo "This file is used by 'make' for keeping track of last install time. If package.json, package-lock.json or elm.json are newer then this file (.installed) then all 'make *' commands that depend on '.installed' know they need to run npm install first." \
> .installed
# Run development server
.PHONY: run
run: .installed
@npx parcel ${entries}
# Build distribution files and place them where they are expected
.PHONY: dist
dist: .installed
@npx parcel build ${entries}
cp -r .well-known/ dist/.well-known/
# Nuke from orbit
clean:
@rm -rf elm-stuff/ dist/ node_modules/
@rm -f .installed
nodemailer = require 'nodemailer'
Firebase = require 'firebase'
config = require 'config-object'
config.load '../config.cson', required: yes
database = new Firebase config.firebase.url
database.authWithCustomToken config.firebase.secret, (error) ->
if error then throw error
transporter = nodemailer.createTransport config.nodemailer
callback = (dataSnapshot) =>
{
company,
email,
description,
processed
} = dataSnapshot.val()
return console.log {processed} if processed
transporter.sendMail
to: config.recipients
subject: "New contact from #{company} (#{email})"
replyTo: email
text: description
(error, info) =>
if error then return console.error error
Object.assign info, date: Date.now()
console.log info
dataSnapshot
.ref()
.child 'processed'
.set info
cancelCallback = (error) =>
throw error
database.on "child_added", callback, cancelCallback
View = require 'teacup-view'
module.exports = new View (attributes) ->
@tag 'form', action: '/', method: 'POST', id: 'contact', =>
@h1 """Let's get in touch"""
@label "Please describe your needs"
@textarea name: "description", required: true, rows: 6
@label "Your contact information (email)"
@input type: "email", name: "email", required: true
@label "Company name"
@input type: "text", name: "company", required: true
@button type: "submit", "Submit"
@div id: 'thank-you', =>
@h1 "Thank you"
@h2 "Your message has been sent. We will contact you shortly."
View = require 'teacup-view'
module.exports = new View (attributes) ->
@section attributes, => @div class: "container", =>
@markdown """
# We are a **full stack** team of **two web programmers** available to be hired for your project.
"""
@div class: 'team', =>
@a
href : "#landing"
class : "teammate tadeusz"
=>
@img
src : '/tadeusz-lazurski-circle-transparent.png'
alt : 'Tadeusz Łazurski face - less than a half of it'
@h3 'Tadeusz Lazurski'
@p 'Full stack developer'
@a
href : "http://lori2lori.rocks"
class : "teammate dorota"
=>
@img
src : '/dorota-cieslinska-circle-transparent.png'
alt : 'Dorota Cieslinska'
@h3 'Dorota Cieslinska'
@p 'Frontend developer'
@article =>
@markdown """
## Area of expertise
We can help you choose **right feature set** and **technology stack** for your product. We have experience in **project management** and **product development** in various types of organisations. You can **outsource your entire project** or it's part to us or hire us to **strenghten your existing team**. We can work remotely or at your office in the Amsterdam area.
## Some of the technologies we use
"""
@grid items: [
src: "/logos/logo-js.svg"
title: "JavaScript"
,
src: "/logos/logo-html5.svg"
title: "HTML"
,
src: "/logos/logo-css3.svg"
title: "CSS"
,
src: "/logos/logo-reactjs.svg"
title: "React.js"
,
src: "/logos/logo-coffee.svg"
title: "CoffeeScript"
,
src: "/logos/logo-backbone.svg"
title: "Backbone.js"
,
src: "/logos/logo-jquery.svg"
title: "jQuery"
,
src: "/logos/logo-node.svg"
title: "Node.js"
,
src: "/logos/logo-rethinkdb.svg"
title: "RethinkDB"
,
src: "/logos/logo-elasticsearch.svg"
title: "ElasticSearch"
,
src: "/logos/logo-socketio.svg"
title: "Socket.IO"
,
src: "/logos/logo-docker.svg"
title: "Docker"
,
src: "/logos/logo-mongodb.svg"
title: "MongoDB"
,
src: "/logos/logo-mysql.svg"
title: "SQL"
]
@contact id: 'contact'
View = require 'teacup-view'
grid_item = View ({ src, title }) ->
@li class: "grid-item", =>
@img { src }
@p title
module.exports = View ({ items }) ->
@ul class: 'grid', =>
grid_item item for item in items
View = require 'teacup-view'
typeform = require './typeform'
module.exports = new View (attributes) ->
@section attributes, => @div class: "container", =>
@header =>
@h1 =>
@raw "<strong>Hello</strong>, my name is Tadeusz."
do @br
@raw "I'm a <strong>full stack web developer</strong>."
@img
class : 'main-image'
src : '/tadeusz-lazurski-circle-transparent.png'
alt : 'Tadeusz Łazurski face - less than a half of it'
@tag 'main', =>
@markdown """
Together with my partner (a frontend developer) we enjoy solving problems using **Node.js**, **React.js** and **CoffeeScript** in the wonderful Amsterdam. You can **[hire us for your project](#freelance)**.
"""
@footer =>
@ul id: 'menu', =>
@li class: 'caption', => @span "Get in touch via"
(@li => @a { href }, => @span label) for label, href of {
'GitHub' : 'https://github.com/lzrski'
'StackOverflow' : 'https://careers.stackoverflow.com/lazurski'
'Twitter' : 'https://twitter.com/lazurski'
'LinkedIn' : 'https://linkedin.com/in/lazurski'
}
# @a
# class : 'source'
# href : 'https://github.com/lzrski/personal-website'
# 'Fork this website at GitHub'
View = require 'teacup-view'
MD = require 'markdown-it'
md = MD breaks: yes, typographer: no
module.exports = View (content) -> @raw md.render content
View = require 'teacup-view'
module.exports = new View ->
@a
href :"https://dorilori.typeform.com/to/KJMtfy"
class : "typeform-share link"
target: "_blank"
data :
mode : 1
"Let's get in touch"
# Fill information and copy this to config.cson
# config.cson is added to .gitignore and stored locally only, don't share it
nodemailer:
service : 'gmail',
auth :
user : 'user@example.com',
pass : '***********'
firebase :
url : 'https://example.firebaseio.com/'
secret : 'copy&paste App secret from Firebase dashboard'
recipients: [
'user@example.com'
'anotheruser@example.com'
]
###
Firebase security rules
{
"rules": {
".read": false,
"$message": {
".write": "!data.exists()"
}
}
}
###
gulp = require 'gulp'
coffee = require 'gulp-coffee'
mocha = require 'gulp-mocha'
sourcemaps = require 'gulp-sourcemaps'
del = require 'del'
webserver = require 'gulp-webserver'
stylus = require 'gulp-stylus'
autoprefixer = require 'gulp-autoprefixer'
through = require 'through2'
browserify = require 'browserify'
watchify = require 'watchify'
coffeeify = require 'coffeeify'
uglify = require 'gulp-uglify'
buffer = require 'vinyl-buffer'
source = require 'vinyl-source-stream'
exorcist = require 'exorcist'
_ = require 'lodash'
# Use common tasks
tasks = require './gulpfile.d'
tasks
clean :
source : 'build'
teacup :
source : 'html/**/*'
components : 'components/*'
destination : 'build'
# Fast browserify builds using watchify
b = watchify browserify _.merge {}, watchify.args,
entries : './scripts/index.coffee'
debug : true
transform : coffeeify
extensions: ['.coffee']
b.on 'log', console.log
gulp.task 'scripts', ->
{ NODE_ENV } = process.env
b
.bundle()
.on 'error', (error) ->
console.trace error
.pipe exorcist './build/bundle.js.map'
.pipe source 'bundle.js'
.pipe buffer()
.pipe if NODE_ENV is 'development' then through.obj() else uglify()
.pipe gulp.dest './build/'
gulp.task 'test', ->
development = process.env.NODE_ENV is 'development'
gulp
.src 'test/*.coffee', read: no
.pipe mocha
reporter : 'spec'
compilers : 'coffee:coffee-script'
.once 'error', (error) ->
console.error 'Tests failed', error
if development
return @emit 'end'
else
process.exit 1
gulp.task 'assets', ->
gulp
.src 'assets/**/*'
.pipe gulp.dest 'build'
gulp.task 'styl', ->
gulp
.src './styles/index.styl'
.pipe sourcemaps.init loadMaps: no
.pipe stylus()
.pipe autoprefixer
browsers : [ '> 5%', 'last 5 versions' ]
cascade : false
.pipe sourcemaps.write '.'
# FIXME: Temporary fix for gulpjs/gulp#1461 until gulpjs/vinyl-fs#128 is ready
.pipe do require './gulpfile.d/helpers/touch'
.pipe gulp.dest './build'
gulp.task 'backend', () =>
gulp
.src './backend/**/*.coffee'
.pipe coffee()
.pipe gulp.dest 'build'
gulp.task 'build', gulp.series [
'clean'
gulp.parallel [
'assets'
'teacup'
'styl'
'scripts'
'backend'
]
'test'
]
gulp.task 'serve', ->
gulp
.src 'build'
.pipe webserver
host : '0.0.0.0'
open : 'http://localhost:8000/'
livereload: yes
gulp.task 'watch', (done) ->
gulp.watch [
'test/**/*'
'package.json'
], gulp.series [
'test'
]
# TODO: More granular watch
gulp.watch [
'assets/**/*'
'scripts/**/*'
'backend/**/*'
'html/**/*'
'components/**/*'
'styles/**/*'
'package.json'
], gulp.series [
'build'
]
gulp.task 'develop', gulp.series [
(done) ->
process.env.NODE_ENV ?= 'development'
do done
'build'
'serve'
'watch'
]
gulp = require 'gulp'
del = require 'del'
{
src
dest
parallel
series
task
watch
} = gulp
module.exports = ({ source }) ->
source ?= 'build/'
task 'clean', ->
del source
gulp = require 'gulp'
coffee = require 'gulp-coffee'
sourcemaps = require 'gulp-sourcemaps'
cached = require 'gulp-cached'
{
src
dest
parallel
series
task
watch
} = gulp
module.exports = ({ source, destination }) ->
source ?= 'src/**/*.coffee'
destination ?= 'build/'
task 'coffee', ->
gulp
.src source
.pipe cached 'coffee'
.pipe sourcemaps.init()
.pipe coffee()
.pipe sourcemaps.write '.'
.pipe dest destination
through = require 'through2'
module.exports = -> through.obj (file, enc, done) ->
file.stat.mtime = new Date
done null, file
# Setup tasks. Takes an object.
module.exports = (tasks) ->
for task, options of tasks
constructor = require "./#{task}"
constructor options
# Eats teacup-views and spits html
gulp = require 'gulp'
through = require 'through2'
rename = require "gulp-rename"
prettify = require 'gulp-prettify'
View = require 'teacup-view'
{ basename } = require 'path'
{ camelize } = require 'underscore.string'
{
src
dest
parallel
series
task
watch
} = gulp
defaults =
sources : 'html/**/*'
components : null
destination : 'build'
module.exports = (options = {}) ->
options[key] ?= value for key, value of defaults
load_components = ->
{ components } = options
return if not components
gulp
.src components, read: no
.pipe through.obj (file, enc, done) ->
# each file should be a module containing Teacup View instance
# i.e. a function, that when called returns HTML string
# Clear cache, otherwise watch will always produce same output
require.cache[file.path] = null
component = {}
name = camelize (basename file.path, '.coffee')
value = require file.path
component[name] = value
View.load_components component
do done
render = ->
{ NODE_ENV } = process.env
gulp
.src options.sources, read: no
.pipe through.obj (file, enc, done) ->
# each file should be a module containing Teacup View instance
# i.e. a function, that when called returns HTML string
# Clear cache, otherwise watch will always produce same output
require.cache[file.path] = null
view = require file.path
html = do view
file.contents = new Buffer html
@push file
do done
.pipe rename extname: '.html'
.pipe if NODE_ENV is 'development' then prettify indent_size: 2 else through.obj()
# FIXME: Temporary fix for gulpjs/gulp#1461 until gulpjs/vinyl-fs#128 is ready
.pipe do require './helpers/touch'
.pipe dest options.destination
task 'teacup', series [
load_components
render
]
gulp = require 'gulp'
mocha = require 'gulp-mocha'
{
src
dest
parallel