Merge remote-tracking branch 'sculpin-old/master'

This commit is contained in:
Oliver Davies 2024-08-01 22:28:21 +01:00
commit 50aa844492
446 changed files with 33070 additions and 0 deletions

20
.editorconfig Normal file
View file

@ -0,0 +1,20 @@
# This file is used by editors and IDEs to unify coding standards
# @see http://EditorConfig.org
# @standards PHP: http://www.php-fig.org/psr/psr-2/
root = true
# Default configuration (applies to all file types)
[*]
charset = utf-8
end_of_line = lf
insert_final_newline = true
trim_trailing_whitespace = true
indent_size = 4
indent_style = space
[*.{css,js,vue}]
indent_size = 2
# Markdown customizations
[*.md]
trim_trailing_whitespace = false

14
.eslintrc.js Normal file
View file

@ -0,0 +1,14 @@
module.exports = {
'env': {
'browser': true,
'es6': true,
"node": true
},
'extends': [
'eslint:recommended',
'plugin:vue/recommended'
],
'plugins': [
'vue'
]
}

6
.gitignore vendored Normal file
View file

@ -0,0 +1,6 @@
/bin/
/node_modules/
/output_*/
/source/build/
/vendor/
/.phpunit.result.cache

14
.php_cs.dist Normal file
View file

@ -0,0 +1,14 @@
<?php
use PhpCsFixer\Config;
use Symfony\Component\Finder\Finder;
$finder = new Finder();
$finder->files()->in(['src', 'tests']);
return Config::create()
->setRules([
'@PSR2' => true,
'array_syntax' => ['syntax' => 'short'],
])
->setFinder($finder);

21
app/SculpinKernel.php Normal file
View file

@ -0,0 +1,21 @@
<?php
use Opdavies\Sculpin\Bundle\ContentGeneratorBundle\SculpinContentGeneratorBundle;
use Opdavies\Sculpin\Bundle\GistEmbedBundle\SculpinGistEmbedBundle;
use Opdavies\Sculpin\Bundle\TwigMarkdownBundle\SculpinTwigMarkdownBundle;
use Sculpin\Bundle\SculpinBundle\HttpKernel\AbstractKernel;
class SculpinKernel extends AbstractKernel
{
/**
* {@inheritdoc}
*/
protected function getAdditionalSculpinBundles(): array
{
return [
SculpinContentGeneratorBundle::class,
SculpinGistEmbedBundle::class,
SculpinTwigMarkdownBundle::class,
];
}
}

View file

@ -0,0 +1,3 @@
availability:
part: no
full: no

View file

@ -0,0 +1,67 @@
companies:
appnovation:
name: Appnovation
logo: appnovation.png
url: https://www.appnovation.com
cti:
name: CTI Digital
logo: cti-digital.png
url: https://www.ctidigital.com
develop_me:
name: Develop Me Training
logo: develop_me.svg
url: https://developme.training
drupal_association:
name: Drupal Association
logo: drupal-association.png
url: https://www.drupal.org/association
freelance:
name: Freelance
horse_country:
name: 'Horse & Country TV'
logo: horse-and-country.jpg
url: http://www.horseandcountry.tv
inviqa:
name: Inviqa
logo: inviqa.jpg
url: https://inviqa.com
lab_class:
name: Lab Class
logo: lab-class.png
url: http://labclass.co.uk
microserve:
name: Microserve
logo: microserve.png
url: https://microserve.io
github: https://github.com/microserve-io
nomensa:
name: Nomensa
logo: nomensa.png
url: http://www.nomensa.com
precedent:
name: Precedent
logo: precedent.jpg
url: http://precedent.com
proctors:
name: 'Proctor & Stevenson'
logo: proctors.jpg
url: http://www.proctors.co.uk
trent:
name: Trent Design
url: http://www.trentdesign.net
zooba:
name: Zooba Ltd

155
app/config/data/events.yml Normal file
View file

@ -0,0 +1,155 @@
events:
blue_conf_19:
name: Blue Conf 2019
location: Cardiff, UK
url: https://blueconf.co.uk
bristol_devops:
name: Bristol Cloud Native & DevOps
location: Bristol, UK
url: https://www.meetup.com/Bristol-Cloud-Native-DevOps
cms_philly_20:
name: CMS Philly
location: Philadelphia, USA
url: https://cmsphilly.org
drupal_bristol:
name: Drupal Bristol
location: Bristol, UK
url: https://www.drupalbristol.org.uk
drupal_dev_days_18:
name: Drupal Developer Days 2018
location: Lisbon, Portugal
url: http://lisbon2018.drupaldays.org
drupal_edinburgh:
name: Drupal Edinburgh
url: https://www.meetup.com/Drupal-Edinburgh
drupal_somerset:
name: Drupal Somerset
location: Glastonbury, UK
drupal_yorkshire:
name: Drupal Yorkshire
location: Leeds, UK
url: https://www.meetup.com/DrupalYorkshire
drupalcamp_brighton_15:
name: DrupalCamp Brighton 2015
location: Brighton, UK
drupalcamp_bristol_16:
name: DrupalCamp Bristol 2016
location: Bristol, UK
url: https://2016.drupalcampbristol.org.uk
drupalcamp_dublin_17:
name: DrupalCamp Dublin 2017
location: Dublin, Ireland
url: http://2017.drupal.ie
drupalcamp_london_14:
name: DrupalCamp London 2014
location: London, UK
drupalcamp_london_15:
name: DrupalCamp London 2015
location: London, UK
drupalcamp_london_16:
name: DrupalCamp London 2016
location: London, UK
drupalcamp_london_17:
name: DrupalCamp London 2017
location: London, UK
drupalcamp_london_18:
name: DrupalCamp London 2018
location: London, UK
drupalcamp_london_19:
name: DrupalCamp London 2019
location: London, UK
url: http://drupalcamp.london
drupalcamp_london_20:
name: DrupalCamp London 2020
location: London, UK
url: http://drupalcamp.london
drupalcamp_north_15:
name: DrupalCamp North 2015
location: Sunderland, UK
url: http://drupalcampnorth.org
drupalcon_eu_19:
name: DrupalCon Europe 2019
location: Amsterdam, NL
url: https://events.drupal.org/amsterdam2019
nomad_php:
name: Nomad PHP
url: https://nomadphp.com
nwdug:
name: NWDUG
location: Manchester, UK
url: http://nwdrupal.org.uk
phpnw_17:
name: PHP North West 2017
location: Manchester, UK
url: http://conference.phpnw.org.uk/phpnw17
php_south_coast_16:
name: PHP South Coast 2016
location: Portsmouth, UK
url: http://2016.phpsouthcoast.co.uk
php_south_wales:
name: PHP South Wales
location: Cardiff, UK
url: https://www.phpsouthwales.uk
phpsw:
name: PHPSW
location: Bristol, UK
url: https://phpsw.uk
php_uk_18:
name: PHP UK Conference 2018
location: London, UK
url: https://www.phpconference.co.uk
ssdc:
name: Swansea Software Development Meetup (SSDC)
location: Swansea, UK
url: https://www.meetup.com/Swansea-Software-Development-Meetup
swdug:
name: SWDUG
location: Cardiff, UK
umbristol:
name: umBristol
location: Bristol, UK
url: http://umbristol.co.uk
unified_diff:
name: 'unified.diff'
location: Cardiff, UK
url: http://unifieddiff.co.uk
wordcamp_bristol_2019:
name: 'WordCamp Bristol 2019'
location: Bristol, UK
url: https://2019.bristol.wordcamp.org
wpchelt:
name: Cheltenham WordPress Meetup
location: Cheltenham, UK
url: https://www.meetup.com/Cheltenham-WordPress-Meetup

45
app/config/data/links.yml Normal file
View file

@ -0,0 +1,45 @@
ansible_galaxy:
url: https://galaxy.ansible.com/opdavies
drupalorg:
name: opdavies
uid: 381388
url: https://www.drupal.org/user/381388
url_new: https://www.drupal.org/u/opdavies
github:
url: https://github.com/opdavies
user: opdavies
gravatar:
url: //www.gravatar.com/avatar/e0f6adcd63d8393e689b327e978d0887.png
joindin:
url: https://joind.in/user/opdavies
linkedin:
url: http://uk.linkedin.com/in/opdavies
npm:
url: https://www.npmjs.com/~opdavies
packagist:
user: opdavies
url: https://packagist.org/users/opdavies
speakerdeck:
url: https://speakerdeck.com/opdavies
twitter:
url: https://twitter.com/opdavies
user: opdavies
wordpress:
url: https://profiles.wordpress.org/opdavies
user: opdavies
youtube:
channel:
url: https://www.youtube.com/channel/UCkeK0qF9HHUPQH_fvn4ghqQ
stream:
url: '%youtube.channel.url%/live'

36
app/config/data/menus.yml Normal file
View file

@ -0,0 +1,36 @@
menus:
main:
about:
title: 'About'
href: '/'
pattern: '^/.$'
articles:
title: 'Articles'
href: '/articles'
pattern: '^/articles/?'
talks:
title: 'Talks'
href: '/talks'
pattern: '^/talks/?'
podcasts:
title: 'Podcasts'
href: '/podcasts'
pattern: '^/podcasts/?'
projects:
title: 'Projects'
href: '/projects'
pattern: '^/projects/?$'
book:
title: 'Book'
href: '/test-driven-drupal'
pattern: '^/test-driven-drupal/?$'
contact:
title: 'Contact'
href: '/contact'
pattern: '^/contact/?'

View file

@ -0,0 +1,435 @@
---
redirects:
- from: about
to: /
- from: articles/2010/04/05/style-drupal-6s-taxonomy-lists-php-css-and-jquery
to: /articles/style-drupal-6s-taxonomy-lists-php-css-and-jquery
- from: articles/2010/04/28/using-imagecache-and-imagecrop-my-portfolio
to: /articles/using-imagecache-and-imagecrop-my-portfolio
- from: articles/2010/05/06/conditional-email-addresses-webform
to: /articles/conditional-email-addresses-webform
- from: articles/2010/05/10/quickly-create-zen-subthemes-using-zenophile
to: /articles/quickly-create-zen-subthemes-using-zenophile
- from: articles/2010/05/25/create-slideshow-multiple-images-using-fancy-slide
to: /articles/create-slideshow-multiple-images-using-fancy-slide
- from: articles/2010/05/29/quickly-import-multiples-images-using-imagefieldimport-module
to: /articles/quickly-import-multiples-images-using-imagefieldimport-module
- from: articles/2010/06/02/improve-jpg-quality-imagecache-and-imageapi
to: /articles/improve-jpg-quality-imagecache-and-imageapi
- from: articles/2010/06/23/create-block-social-media-icons-using-cck-views-and-nodequeue
to: /articles/create-block-social-media-icons-using-cck-views-and-nodequeue
- from: articles/2010/06/25/10-useful-drupal-6-modules
to: /articles/10-useful-drupal-6-modules
- from: articles/2010/06/28/create-flickr-photo-gallery-using-feeds-cck-and-views
to: /articles/create-flickr-photo-gallery-using-feeds-cck-and-views
- from: articles/2010/07/01/change-content-type-multiple-nodes-using-sql
to: /articles/change-content-type-multiple-nodes-using-sql
- from: articles/2010/07/02/create-virtual-hosts-mac-os-x-using-virtualhostx
to: /articles/create-virtual-hosts-mac-os-x-using-virtualhostx
- from: articles/2010/07/07/add-taxonomy-term-multiple-nodes-using-sql
to: /articles/add-taxonomy-term-multiple-nodes-using-sql
- from: articles/2010/07/12/review-teleport-module
to: /articles/review-teleport-module
- from: articles/2010/08/10/review-adminhover-module
to: /articles/review-adminhover-module
- from: articles/2010/08/11/create-better-photo-gallery-drupal-part-1
to: /articles/create-better-photo-gallery-drupal-part-1
- from: articles/2010/08/17/create-better-photo-gallery-drupal-part-2
to: /articles/create-better-photo-gallery-drupal-part-2
- from: articles/2010/08/20/review-image-caption-module
to: /articles/review-image-caption-module
- from: articles/2010/09/26/south-wales-drupal-user-group
to: /articles/south-wales-drupal-user-group
- from: articles/2010/10/10/create-and-apply-patches
to: /articles/create-and-apply-patches
- from: articles/2010/10/13/create-better-photo-gallery-drupal-part-3
to: /articles/create-better-photo-gallery-drupal-part-3
- from: articles/2010/10/22/create-better-photo-gallery-drupal-part-21
to: /articles/create-better-photo-gallery-drupal-part-21
- from: articles/2010/11/04/use-regular-expressions-search-and-replace-coda-or-textmate
to: /articles/use-regular-expressions-search-and-replace-coda-or-textmate
- from: articles/2011/02/14/easily-embed-typekit-fonts-your-drupal-website
to: /articles/easily-embed-typekit-fonts-your-drupal-website
- from: articles/2011/03/15/display-number-facebook-fans-php
to: /articles/display-number-facebook-fans-php
- from: articles/2011/03/31/proctor-stevenson
to: /articles/proctor-stevenson
- from: articles/2011/05/20/proctors-hosting-next-drupal-meetup
to: /articles/proctors-hosting-next-drupal-meetup
- from: articles/2011/05/23/imagefield-import-archive
to: /articles/imagefield-import-archive
- from: articles/2011/08/28/create-multigroups-drupal-7-using-field-collections
to: /articles/create-multigroups-drupal-7-using-field-collections
- from: articles/2011/10/19/install-and-configure-subversion-svn-server-ubuntu
to: /articles/install-and-configure-subversion-svn-server-ubuntu
- from: articles/2012/01/04/site-upgraded-drupal-7
to: /articles/site-upgraded-drupal-7
- from: articles/2012/02/01/use-authorized-keys-create-passwordless-ssh-connection
to: /articles/use-authorized-keys-create-passwordless-ssh-connection
- from: articles/2012/04/16/create-omega-subtheme-less-css-preprocessor-using-omega-tools-and-drush
to: /articles/create-omega-subtheme-less-css-preprocessor-using-omega-tools-and-drush
- from: articles/2012/04/17/installing-nagios-centos
to: /articles/installing-nagios-centos
- from: articles/2012/04/19/adding-custom-theme-templates-drupal-7
to: /articles/adding-custom-theme-templates-drupal-7
- from: articles/2012/05/23/add-date-popup-calendar-custom-form
to: /articles/add-date-popup-calendar-custom-form
- from: articles/2012/05/23/checkout-specific-revision-svn-command-line
to: /articles/checkout-specific-revision-svn-command-line
- from: articles/2012/05/23/forward-one-domain-another-using-mod-rewrite-and-htaccess
to: /articles/forward-one-domain-another-using-mod-rewrite-and-htaccess
- from: articles/2012/05/23/prevent-apache-displaying-text-files-within-web-browser
to: /articles/prevent-apache-displaying-text-files-within-web-browser
- from: articles/2012/05/23/writing-info-file-drupal-7-theme
to: /articles/writing-info-file-drupal-7-theme
- from: articles/2012/05/24/dividing-drupals-process-and-preprocess-functions-separate-files
to: /articles/dividing-drupals-process-and-preprocess-functions-separate-files
- from: articles/2012/07/12/my-new-drupal-modules
to: /articles/my-new-drupal-modules
- from: articles/2012/07/14/install-nomensa-media-player-drupal
to: /articles/install-nomensa-media-player-drupal
- from: articles/2012/07/27/writing-article-linux-journal
to: /articles/writing-article-linux-journal
- from: articles/2012/08/18/display-custom-menu-drupal-7-theme-template-file
to: /articles/display-custom-menu-drupal-7-theme-template-file
- from: articles/2012/09/06/reflections-speaking-unifieddiff
to: /articles/reflections-speaking-unifieddiff
- from: articles/2012/10/25/my-sublime-text-2-settings
to: /articles/my-sublime-text-2-settings
- from: articles/2012/11/15/accessible-bristol-site-launched
to: /articles/accessible-bristol-site-launched
- from: articles/2012/11/17/open-sublime-text-2-mac-os-x-command-line
to: /articles/open-sublime-text-2-mac-os-x-command-line
- from: articles/2012/12/06/use-sass-and-compass-drupal-7-using-sassy
to: /articles/use-sass-and-compass-drupal-7-using-sassy
- from: articles/2013/01/09/checking-if-user-logged-drupal-right-way
to: /articles/checking-if-user-logged-drupal-right-way
- from: articles/2013/02/16/creating-and-using-custom-tokens-drupal-7
to: /articles/creating-and-using-custom-tokens-drupal-7
- from: articles/2013/03/02/quickest-way-install-sublime-text-2-ubuntu
to: /articles/quickest-way-install-sublime-text-2-ubuntu
- from: articles/2013/04/20/leaving-nomensa-joining-precedent
to: /articles/leaving-nomensa-joining-precedent
- from: articles/2013/04/27/display-git-branch-or-tag-names-your-bash-prompt
to: /articles/display-git-branch-or-tag-names-your-bash-prompt
- from: articles/2013/06/13/some-useful-links-using-simpletest-drupal
to: /articles/some-useful-links-using-simpletest-drupal
- from: articles/2013/07/17/creating-local-and-staging-sites-drupals-domain-module-enabled
to: /articles/creating-local-and-staging-sites-drupals-domain-module-enabled
- from: articles/2013/07/26/going-drupalcon
to: /articles/going-drupalcon
- from: articles/2013/09/06/create-a-zen-sub-theme-using-drush
to: /articles/create-a-zen-sub-theme-using-drush
- from: articles/2013/11/19/dont-bootstrap-drupal-use-drush
to: /articles/dont-bootstrap-drupal-use-drush
- from: articles/2013/11/27/useful-vagrant-commands
to: /articles/useful-vagrant-commands
- from: articles/2013/12/24/quickly-apply-patches-using-git-and-curl-or-wget
to: /articles/quickly-apply-patches-using-git-and-curl-or-wget
- from: articles/2013/12/31/download-different-versions-drupal-drush
to: /articles/download-different-versions-drupal-drush
- from: articles/2014/01/15/some-useful-git-aliases
to: /articles/some-useful-git-aliases
- from: articles/2014/02/09/drupalcamp-london-2014
to: /articles/drupalcamp-london-2014
- from: articles/2014/03/03/what-git-flow
to: /articles/what-git-flow
- from: articles/2014/05/03/drupal-association
to: /articles/drupal-association
- from: articles/2014/05/06/thanks
to: /articles/thanks
- from: articles/2014/05/21/git-format-patch
to: /articles/git-format-patch
- from: articles/2014/07/02/drush-make-drupalbristol
to: /articles/drush-make-drupalbristol
- from: articles/2014/10/06/fix-vagrant-loading-wrong-virtual-machine
to: /articles/fix-vagrant-loading-wrong-virtual-machine
- from: articles/2014/10/21/updating-features-and-adding-components-using-drush
to: /articles/updating-features-and-adding-components-using-drush
- from: articles/2014/11/18/include-css-fonts-using-sass-each-loop
to: /articles/include-css-fonts-using-sass-each-loop
- from: articles/2014/11/20/using-remote-files-when-developing-locally-with-stage-file-proxy-module
to: /articles/using-remote-files-when-developing-locally-with-stage-file-proxy-module
- from: articles/2014/11/27/pantheon-settings-files
to: /articles/pantheon-settings-files
- from: articles/2014/12/20/include-local-drupal-settings-file-environment-configuration-and-overrides
to: /articles/include-local-drupal-settings-file-environment-configuration-and-overrides
- from: articles/2015/04/03/how-to-define-a-minimum-drupal-core-version
to: /articles/how-to-define-a-minimum-drupal-core-version
- from: articles/2015/06/18/updating-forked-repositories-on-github
to: /articles/updating-forked-repositories-on-github
- from: articles/2015/07/19/sculpin-twig-resources
to: /articles/sculpin-twig-resources
- from: articles/2015/07/21/automating-sculpin-jenkins
to: /articles/automating-sculpin-jenkins
- from: articles/2015/12/22/programmatically-load-an-entityform-in-drupal-7
to: /articles/programmatically-load-an-entityform-in-drupal-7
- from: articles/2016/02/15/announcing-the-drupal-vm-generator
to: /articles/announcing-the-drupal-vm-generator
- from: articles/2016/05/03/simplifying-drupal-migrations-with-xautoload
to: /articles/simplifying-drupal-migrations-with-xautoload
- from: articles/2016/07/15/building-gmail-filters-with-php
to: /articles/building-gmail-filters-with-php
- from: articles/2016/12/30/drupal-vm-generator-291-released
to: /articles/drupal-vm-generator-291-released
- from: articles/2017/01/07/easier-sculpin-commands-with-composer-and-npm-scripts
to: /articles/easier-sculpin-commands-with-composer-and-npm-scripts
- from: articles/2017/01/31/nginx-redirects-with-query-string-arguments
to: /articles/nginx-redirects-with-query-string-arguments
- from: articles/2017/05/05/fixing-drupal-simpletest-docker
to: /articles/2017/05/05/fixing-drupal-simpletest-issues-inside-docker-containers
- from: articles/2017/05/05/fixing-drupal-simpletest-issues-inside-docker-containers
to: /articles/fixing-drupal-simpletest-issues-inside-docker-containers
- from: articles/2017/06/09/introducing-the-drupal-meetups-twitterbot
to: /articles/introducing-the-drupal-meetups-twitterbot
- from: articles/2017/11/07/tdd-test-driven-drupal
to: /articles/tdd-test-driven-drupal
- from: articles/2017/11/07/writing-drupal-module-test-driven-development-tdd
to: /articles/2017/11/07/tdd-test-driven-drupal
- from: articles/2018/01/30/drupalcamp-bristol-2018
to: /articles/drupalcamp-bristol-2018
- from: articles/2018/02/05/using-tailwind-css-in-your-drupal-theme
to: /articles/using-tailwind-css-in-your-drupal-theme
- from: articles/2018/02/27/looking-forward-to-drupalcamp-london
to: /articles/looking-forward-to-drupalcamp-london
- from: articles/2018/02/27/queuing-private-messages-in-drupal-8
to: /articles/queuing-private-messages-in-drupal-8
- from: articles/2018/02/28/building-the-new-phpsw-website
to: /articles/building-the-new-phpsw-website
- from: articles/2018/03/02/yay-the-mediacurrent-contrib-half-hour-is-back
to: /articles/yay-the-mediacurrent-contrib-half-hour-is-back
- from: articles/2018/03/04/tweets-from-drupalcamp-london
to: /articles/tweets-from-drupalcamp-london
- from: articles/2018/05/06/creating-a-custom-phpunit-command-for-docksal
to: /articles/creating-a-custom-phpunit-command-for-docksal
- from: articles/announcing-the-drupal-vm-config-generator
to: /articles/announcing-the-drupal-vm-generator
- from: articles/drush-make-drupalbristol
to: /talks/drush-make-drupalbristol
- from: articles/system-users-null-users
to: /articles/null-users-and-system-users-in-drupal
- from: articles/tweets-from-drupalcamp-london
to: /articles/tweets-drupalcamp-london
- from: blog
to: /articles
- from: blog.xml
to: /feed
- from: book
to: /test-driven-drupal
- from: consulting
to: /
- from: cv
to: https://cv.oliverdavies.uk
- from: drupal
to: '%drupalorg.url%'
- from: drupalgive
to: https://www.drupal.org/u/opdavies
- from: experience
to: https://cv.oliverdavies.uk
- from: git-flow
to: /talks/git-flow
- from: github
to: '%github.url%'
- from: joindin
to: '%joindin.url%'
- from: linkedin
to: '%linkedin.url%'
- from: packagist
to: '%packagist.url%'
- from: services
to: /experience
- from: slides/bristol-dug/drupal-vm-generator
to: http://opdavies.github.io/slides-drupal-vm-generator
- from: slides/phpsw/building-static-websites-with-sculpin
to: https://opdavies.github.io/slides-phpsw-sculpin
- from: speakerdeck
to: '%speakerdeck.url%'
- from: speaking
to: /talks
- from: talks/2012/09/05/what-is-this-drupal-thing-unified-diff
to: /talks/what-is-this-drupal-thing
- from: talks/2013/07/10/drupal-ldap-swdug
to: /talks/drupal-ldap
- from: talks/2014/03/01/git-flow-drupalcamp-london-2014
to: /talks/git-flow
- from: talks/2014/07/02/drush-make-drupalbristol-drupal-bristol
to: /talks/drush-make-drupalbristol
- from: talks/2014/08/19/drupal-association-swdug
to: /talks/drupal-association
- from: talks/2015/01/18/drupalorg-2015-drupalcamp-brighton-2015
to: /talks/drupalorg-in-2015-whats-coming-next
- from: talks/2015/02/28/drupalorg-2015-drupalcamp-london-2015
to: /talks/drupalorg-in-2015-whats-coming-next
- from: talks/2015/04/08/drupal-8-phpsw
to: /talks/drupal-8
- from: talks/2015/07/25/test-drive-twig-with-sculpin-drupalcamp-north-2015
to: /talks/test-drive-twig-with-sculpin
- from: talks/2015/08/25/dancing-for-drupal-umbristol
to: /talks/dancing-for-drupal
- from: talks/2015/10/14/sculpin-phpsw
to: /talks/sculpin
- from: talks/2016/03/05/drupal-8-module-development-drupalcamp-london-2016
to: /talks/getting-started-with-drupal-8-module-development
- from: talks/2016/03/09/drupal-vm-generator-nwdug
to: /talks/drupal-vm-generator
- from: talks/2016/04/02/drupal-vm-generator-drupal-bristol
to: /talks/drupal-vm-generator
- from: talks/2016/06/11/drupal-8-rejoining-the-herd-php-south-coast-2016
to: /talks/drupal-8-rejoining-the-herd
- from: talks/2016/07/23/drupal-vm-meet-symfony-console-drupalcamp-bristol-2016
to: /talks/drupal-vm-meet-symfony-console
- from: talks/2016/11/09/drupal-development-with-composer-phpsw
to: /talks/drupal-development-with-composer
- from: talks/2016/11/17/goodbye-drush-make-hello-composer-drupal-bristol
to: /talks/goodbye-drush-make-hello-composer
- from: talks/2017/01/18/getting-your-data-into-drupal-8-drupal-bristol
to: /talks/getting-your-data-into-drupal-8
- from: talks/2017/03/04/getting-your-data-into-drupal-8-drupalcamp-london-2017
to: /talks/getting-your-data-into-drupal-8
- from: talks/archive
to: /talks
- from: talks/deploying-php-applications-with-fabric
to: /talks/deploying-php-fabric
- from: talks/drupal-vm-generator-2
to: /talks/drupal-vm-generator
- from: talks/drupalorg-2015-2
to: /talks/drupalorg-2015
- from: talks/drupalorg-in-2015-whats-coming-next
to: /talks/drupalorg-2015
- from: talks/getting-started-with-drupal-8-module-development
to: /drupal-8-module-development
- from: talks/sculpin
to: /talks/building-static-websites-sculpin
- from: talks/using-laravel-collections-outside-laravel
to: /talks/using-illuminate-collections-outside-laravel
- from: terms-and-conditions
to: /terms
- from: twitter
to: '%twitter.url%'
- from: work
to: /experience
- from: youtube
to: '%youtube.channel.url%'
- { from: 'automatically-updating-talk-created-date', to: 'https://gist.github.com/opdavies/4e75e1753d8603113f07f8264bb783d6' }
- { from: 'speaking-videos', to: 'https://www.youtube.com/playlist?list=PLHn41Ay7w7kfAzczswrANch5oHAPZBlvu' }
- { from: 'talks-offer-tweet', to: 'https://twitter.com/opdavies/status/1250870367712935938' }
- { from: testing-drupal, to: https://www.oliverdavies.uk/talks/tdd-test-driven-drupal }
- { from: testing-drupal-intro, to: https://inviqa.com/blog/drupal-automated-testing-introduction }
- { from: talks/ansible-ansistrano, to: https://www.oliverdavies.uk/talks/deploying-php-ansible-ansistrano }
# Moved from opdavi.es
- { from: 2PxmyqP, to: /articles/examples-of-laravel-collections-in-drupal }
- { from: 39CoG, to: /articles/drupalcamp-london-testing-workshop }
- { from: 3eGQr, to: https://github.com/howToCodeWell/howToCodeWellFM/blob/c927e0b3589f1d7375002f7fd70f0bfc9fc90449/composer.json#L17 }
- { from: 6i3YZ, to: https://www.youtube.com/watch?v=vUK5sEbd-dk }
- { from: 6UhLN, to: https://github.com/opdavies/sculpin-twig-markdown-bundle/pull/1 }
- { from: 9rv0Z, to: https://www.drupal.org/project/override_node_options/issues/3109852 }
- { from: acquia-certifications, to: https://certification.acquia.com/registry?fname=Oliver&lname=Davies&city=&state=&country=United+Kingdom&org=&exam=All }
- { from: ansible, to: https://galaxy.ansible.com/opdavies }
- { from: ansible-molecule, to: /articles/test-driven-ansible-role-development-molecule }
- { from: ansistrano-code, to: https://github.com/opdavies/dransible }
- { from: ansistrano-demo, to: https://www.youtube.com/watch?v=PLS4ET7FAcU }
- { from: ansistrano-slides, to: /talks/deploying-php-ansible-ansistrano }
- { from: BhMZi, to: https://git.drupalcode.org/search?utf8=%E2%9C%93&snippets=&scope=&repository_ref=8.x-1.x&search=baz&project_id=23203 }
- { from: cms-philly, to: /articles/presenting-on-tailwind-css-and-ansible-at-cms-philly }
- { from: contrib-half-hour, to: https://www.youtube.com/playlist?list=PLu-MxhbnjI9rHroPvZO5LEUhr58Yl0j_F }
- { from: contribution-day, to: https://github.com/microserve-io/contribution-day/ }
- { from: d0P5z, to: /talks/drupal-8-php-libraries-drupalorg-api }
- { from: dcbristol-cfp, to: https://www.papercall.io/drupalcamp-bristol-2019 }
- { from: dcbristol17-videos, to: https://www.youtube.com/playlist?list=PLOwPvExSyLLngtd6R4PUD9MCXa6QL_obA }
- { from: dcbristol19-announced, to: /articles/drupalcamp-bristol-2019-speakers-sessions-announced }
- { from: dclondon-sat, to: https://drupalcamp.london/schedule/saturday }
- { from: dclondon-sun, to: https://drupalcamp.london/schedule/sunday }
- { from: dclondon20, to: /articles/drupalcamp-london-testing-workshop }
- { from: deploying-php-ansible, to: /talks/deploying-php-ansible-ansistrano }
- { from: dks7E, to: https://www.youtube.com/watch?v=PLS4ET7FAcU }
- { from: do-library, to: https://github.com/opdavies/drupalorg-api-php }
- { from: do-projects, to: https://github.com/opdavies/drupal-module-drupalorg-projects }
- { from: docksal-phpunit-phpstorm, to: /articles/running-phpunit-tests-docksal-phpstorm }
- { from: docksal-posts, to: /articles/tags/docksal }
- { from: dransible, to: https://github.com/opdavies/dransible }
- { from: drupal-bristol-march-19, to: https://docs.google.com/presentation/d/1pk9LIN-hHX73kvDdo-lzgmKlAeH33_K_uvI0t7A-rvY/edit?usp=sharing }
- { from: drupal-core-testing-gate, to: https://www.drupal.org/core/gates#testing }
- { from: drupal-first-time-issues, to: https://www.drupal.org/project/issues/search?text=&projects=&assigned=&submitted=&project_issue_followers=&status%5B%5D=Open&issue_tags_op=%3D&issue_tags=Novice }
- { from: drupal-forum-post, to: http://www.webmaster-forums.net/webmasters-corner/developing-my-website-using-php-and-mysql#comment-1231537 }
- { from: drupal-marketplace-uk, to: https://www.drupal.org/drupal-services?offices%5B%5D=24460 }
- { from: drupal-meetups-twitterbot, to: /articles/introducing-the-drupal-meetups-twitterbot }
- { from: drupal-novice-issues, to: https://www.drupal.org/project/issues/search?text=&projects=&assigned=&submitted=&project_issue_followers=&status%5B%5D=Open&issue_tags_op=%3D&issue_tags=Novice }
- { from: drupal-tailwind-demo, to: https://www.youtube.com/watch?v=1eM-Gw6GI4g }
- { from: drupal-tailwindcss, to: https://www.drupal.org/project/tailwindcss }
- { from: drupal-vuejs, to: /talks/decoupling-drupal-vuejs/ }
- { from: drupalcamp-london-2019-tickets, to: /articles/drupalcamp-london-2019-tickets }
- { from: drupalorg-project-issues, to: https://www.drupal.org/project/issues/search?projects=Override+Node+Options%2C+Tailwind+CSS+Starter+Kit%2C+Block+ARIA+Landmark+Roles%2C+Copyright+Block+module%2C+System+User%2C+Null+User%2C+Collection+class%2C+Pathauto+Menu+Link%2C+Webform+ARIA&project_issue_followers=&status%5B%5D=1&status%5B%5D=13&status%5B%5D=8&status%5B%5D=14&status%5B%5D=15&issue_tags_op=%3D }
- { from: drupalversary, to: https://github.com/opdavies/drupal-module-drupalversary }
- { from: elewant, to: https://elewant.com/shepherd/admire/opdavies }
- { from: first-drupal-core-issue, to: https://www.drupal.org/project/drupal/issues/753898 }
- { from: first-npm-package, to: https://www.npmjs.com/package/tailwindcss-vuejs }
- { from: freeagent, to: https://opdavies.freeagent.com }
- { from: gitlab, to: https://gitlab.com/opdavies }
- { from: gitstore, to: https://enjoy.gitstore.app/maintainers/opdavies }
- { from: gmail-filters, to: https://gitlab.com/opdavies/gmail-filters }
- { from: join-php-south-wales-slack, to: https://join.slack.com/t/phpsouthwales/shared_invite/zt-4vuetc43-AvtEK1WqNzp5k1w4yWKOJA }
- { from: jy6rW, to: https://www.meetup.com/PHP-South-Wales/events/264731393 }
- { from: kB6Jd, to: /articles/running-drupal-with-symfony-local-server/ }
- { from: kmDRA, to: https://www.bbc.co.uk/news/uk-46561779 }
- { from: london-half-term-map, to: https://www.google.com/maps/d/u/0/viewer?mid=1d-7ruqjlm2vKF_Fwhu_-5CDfr2TyUuhB&hl=en&ll=51.50411420613797%2C-0.12409831347656564&z=13 }
- { from: luke-dinosaurs, to: https://luke-dinosaurs.netlify.com/ }
- { from: luke-recycling, to: https://luke-recycling.netlify.com/ }
- { from: microserve-issues, to: https://www.drupal.org/project/issues/search?status[]=Open&issue_tags=Microserve }
- { from: microserve-issues-need-review, to: https://www.drupal.org/project/issues/search?projects=&project_issue_followers=&status%5B%5D=8&issue_tags_op=%3D&issue_tags=Microserve }
- { from: NBi5h, to: https://git.drupalcode.org/search?utf8=%E2%9C%93&search=bar&group_id=&project_id=23203&search_code=true&repository_ref=8.x-1.x&nav_source=navbar }
- { from: npm, to: https://www.npmjs.com/~opdavies }
- { from: oFlkS, to: /articles/test-driven-drupal-on-gitstore-leanpub }
- { from: P5KQ5, to: https://www.npmjs.com/package/tailwindcss-skip-link }
- { from: photo-lab-fun-family-portraits, to: https://www.apple.com/uk/today/event/photo-lab-fun-family-portraits/6512343695143329889 }
- { from: php-ansible, to: /talks/deploying-php-ansible-ansistrano }
- { from: php-south-wales-sept-19, to: https://joind.in/event/php-south-wales---september-2019-double-docker }
- { from: php-south-wales-slack-invite, to: https://join.slack.com/t/phpsouthwales/shared_invite/zt-4vuetc43-AvtEK1WqNzp5k1w4yWKOJA }
- { from: php-south-wales-videos, to: https://www.youtube.com/channel/UCzQRSSaIV2Ajvl81BxPQDZA }
- { from: pv176, to: https://www.sainsburys.co.uk/shop/gb/groceries/paper---notebooks-44/sainsburys-home-midnight-opulence-a4-floral-notebook-133870966-p }
- { from: qSHAl, to: /articles/published-my-first-npm-package/ }
- { from: qT1Rb, to: https://github.com/opdavies/drupal-meetups-twitterbot }
- { from: rebuilding-acquia, to: https://rebuilding-acquia.oliverdavies.uk }
- { from: rebuilding-bartik, to: /articles/rebuilding-bartik-with-vuejs-tailwind-css }
- { from: rebuilding-platformsh, to: https://rebuilding-platformsh.oliverdavies.uk }
- { from: rk29B, to: https://www.meetup.com/PHP-South-Wales/events/268422525 }
- { from: ruralelec-slider, to: https://www.youtube.com/watch?v=-x80ymicm5E }
- { from: S8ZDA, to: /articles/rebuilding-bartik-with-vuejs-tailwind-css-part-2 }
- { from: s9MjJ, to: https://symfonycasts.com/screencast/symfony }
- { from: sculpin-encore-versioning, to: https://github.com/opdavies/oliverdavies.uk/commit/d192b04aefa6e7a21bfc1f2e0fe0a16111e0e8a2 }
- { from: sIGnJ, to: https://microserve.io }
- { from: skills, to: https://opdavies-skills-tailwindcss.netlify.com/ }
- { from: sprint-day, to: https://github.com/microserve-io/contribution-day/ }
- { from: sprint-setup, to: https://github.com/microserve-io/contribution-day/ }
- { from: stream, to: https://www.youtube.com/channel/UCkeK0qF9HHUPQH_fvn4ghqQ/live }
- { from: swap-markdown-parser, to: https://github.com/opdavies/sculpin-twig-markdown-bundle-example/tree/swap-markdown-parser }
- { from: symfony-server, to: /articles/running-drupal-with-symfony-local-server }
- { from: symfonylive, to: /articles/live-blogging-symfonylive-london }
- { from: symposium, to: https://symposiumapp.com/u/opdavies }
- { from: tailwind-repos, to: https://github.com/opdavies?utf8=%E2%9C%93&tab=repositories&q=tailwindcss }
- { from: tailwind-talk, to: /talks/taking-flight-with-tailwind-css }
- { from: tailwindcss-demo, to: http://tailwindcss-demo.oliverdavies.uk/ }
- { from: talks/tailwind, to: /talks/taking-flight-with-tailwind-css/ }
- { from: tdd-blog, to: https://github.com/opdavies/drupal-module-tdd-blog }
- { from: tdd-test-driven-drupal, to: /talks/tdd-test-driven-drupal/ }
- { from: testing-tailwind-plugins, to: /articles/testing-tailwindcss-plugins-with-jest }
- { from: testing-workshop, to: https://github.com/opdavies/workshop-drupal-automated-testing }
- { from: testing-workshop-code, to: https://github.com/opdavies/workshop-drupal-automated-testing-code }
- { from: todoist-filters, to: https://gist.github.com/opdavies/6709fbdac5c3babbd94137bcc8b8e3c2 }
- { from: twitter-tweaks, to: https://github.com/opdavies/chrome-extension-twitter-tweaks }
- { from: uxbjV, to: https://www.drupal.org/project/copyright_block }
- { from: vyTEF, to: https://www.npmjs.com/package/tailwindcss-vuejs }
- { from: webpack-encore-pcss-regex, to: https://regexr.com/51iaf }
- { from: Wh48P, to: https://github.com/opdavies/oliverdavies.uk/blob/master/source/_partials/talk/video.html.twig }
- { from: wordcamp-bristol-tailwindcss, to: https://2019.bristol.wordcamp.org/session/taking-flight-with-tailwind-css }
- { from: wordpress-tailwind, to: https://github.com/opdavies/wordcamp-bristol-2019 }
- { from: workshop-drupal-testing, to: https://github.com/opdavies/workshop-drupal-automated-testing }
- { from: wp-tailwind, to: https://wp-tailwind.oliverdavies.uk }
- { from: wp-tailwind-repo, to: https://github.com/opdavies/wordcamp-bristol-2019 }
- { from: wp-tailwind-starter, to: https://github.com/opdavies/wordpress-tailwindcss-startker-kit }
- { from: wp-tailwind-static, to: https://wp-tailwind.oliverdavies.uk }
- { from: XbzS2, to: https://github.com/opdavies/gmail-filter-builder }
- { from: YilTZ, to: https://drupalcamp.london/tickets/training }
- { from: YK1VH, to: /articles/psr4-autoloading-test-cases-drupal-7 }
- { from: yXhoS, to: /talks/things-you-should-know-about-php }

3
app/config/data/work.yml Normal file
View file

@ -0,0 +1,3 @@
work:
role: Senior Software Engineer and Technical Team Lead
company: inviqa

View file

@ -0,0 +1,27 @@
sculpin:
ignore: ['**/.DS*', '**/*.swp']
sculpin_content_types:
pages:
permalink: /:basename/
posts:
permalink: articles/:basename/
taxonomies: [tags]
talks:
permalink: talks/:basename/
taxonomies: [tags]
parameters:
asset.manifest_dir: '%sculpin.source_dir%'
services:
App\Asset\TwigExtension\EncoreExtension:
autowire: true
arguments:
$manifestDir: '%asset.manifest_dir%'
tags:
- { name: twig.extension }
App\Talk\TwigExtension\TalksExtension:
tags:
- { name: twig.extension }

View file

@ -0,0 +1,23 @@
title: Oliver Davies
subtitle: Full Stack Web Developer (Drupal, Symfony, Laravel, Linux)
description: 'Oliver Davies, Drupal Developer'
email: oliver+website@oliverdavies.uk
apple_touch_icon_sizes: [ 57, 114, 72, 144, 60, 120, 76, 152 ]
favicon_sizes: [ 160, 96, 32, 16 ]
author: Oliver Davies
avatar:
url: /images/me-precedent.jpg
favicon:
url: /images/me-phpnw.png
imports:
- data/availability.yml
- data/companies.yml
- data/events.yml
- data/links.yml
- data/menus.yml
- data/redirects.yml
- data/work.yml

View file

@ -0,0 +1,7 @@
---
imports:
- sculpin_site.yml
url: https://www.oliverdavies.uk
short_url: oliverdavies.uk
google_analytics:
id: UA-11967257-1

11
assets/css/app.pcss Normal file
View file

@ -0,0 +1,11 @@
@import 'tailwindcss/base';
@import './custom-base.pcss';
@import 'tailwindcss/components';
@import './custom-components.pcss';
@import 'highlightjs/styles/github-gist';
@import './libraries/hljs.pcss';
@import 'tailwindcss/utilities';
@import './custom-utilities.pcss';

View file

@ -0,0 +1,14 @@
.button {
@apply py-2 px-3 inline-block border border-blue-600;
@apply text-sm text-white no-underline bg-blue-600 rounded;
&:focus {
@apply py-2 px-3 m-0
}
&:active,
&:focus,
&:hover {
@apply bg-white text-blue-600
}
}

View file

@ -0,0 +1,3 @@
.container {
@apply w-full max-w-5xl px-4 mx-auto
}

View file

@ -0,0 +1,5 @@
p.lead {
@screen md {
@apply text-lg
}
}

View file

@ -0,0 +1,111 @@
.markup {
a {
@apply underline;
&:hover {
@apply no-underline
}
&:focus {
@apply p-px -m-px bg-blue-700 text-white outline-none
}
}
p {
@apply leading-relaxed;
+ p {
@apply mt-4
}
}
ol {
@apply list-decimal
}
ul {
@apply list-disc;
}
ol,
ul {
@apply pl-5;
li + li {
@apply mt-2
}
}
p {
+ blockquote,
+ ol,
+ ul,
+ div[v-pre] {
@apply mt-4
}
}
blockquote + * {
@apply mt-4
}
code {
@apply -my-px px-1 py-px border border-gray-400 text-sm bg-gray-200
}
pre {
@apply border-l-3 border-gray-400 text-sm bg-gray-200;
code {
@apply p-6 block border-none leading-loose text-sm overflow-x-scroll
}
}
* + pre,
* + div[v-pre] {
@apply my-4
}
img,
figure {
@apply my-8
}
figure {
img {
@apply m-0
}
figcaption {
@apply mt-3
}
}
h2 {
@apply leading-tight
}
* + h2 {
@apply mt-8
}
h2 + * {
@apply mt-4
}
h3 {
@apply text-xl font-bold leading-tight
}
* + h3 {
@apply mt-6
}
h3 + * {
@apply mt-2
}
h2 + h3 {
@apply mt-4
}
}

View file

@ -0,0 +1,15 @@
.note {
@apply bg-blue-200 border-blue-600 border-l-4 mb-4 p-4 rounded;
> *:not(:first-child) {
@apply mt-6
}
p a {
@apply text-black underline;
&:hover {
@apply no-underline
}
}
}

View file

@ -0,0 +1,18 @@
.table {
@apply w-full;
th {
@apply bg-gray-200 text-left
}
th,
td {
@apply px-4 py-2 border border-solid border-gray-300
}
}
table.is-striped {
tbody > tr:not(:nth-child(odd)) td {
@apply bg-gray-100
}
}

View file

@ -0,0 +1,9 @@
.video-full {
@apply w-full relative;
padding-top: 56.25%;
iframe,
embed {
@apply absolute h-full left-0 top-0 w-full
}
}

View file

@ -0,0 +1,3 @@
.widget {
@apply block mb-6
}

View file

@ -0,0 +1,7 @@
.wrap {
@apply w-full max-w-3xl mx-auto;
&.is-wide {
@apply max-w-5xl
}
}

View file

@ -0,0 +1,27 @@
h1, h2, h3 {
@apply font-bold
}
h1 {
@apply text-3xl
}
h2 {
@apply text-2xl
}
img {
@apply max-w-full h-auto
}
a {
@apply text-blue-700 no-underline;
&:hover {
@apply underline
}
}
blockquote {
@apply pl-5 border-l-4 border-gray-300 italic
}

View file

@ -0,0 +1,9 @@
@import './components/button.pcss';
@import './components/container.pcss';
@import './components/lead.pcss';
@import './components/markup.pcss';
@import './components/note.pcss';
@import './components/table.pcss';
@import './components/video.pcss';
@import './components/widget.pcss';
@import './components/wrap.pcss';

View file

@ -0,0 +1,3 @@
.no-js .js-hidden {
display: none
}

View file

@ -0,0 +1,3 @@
.hljs {
@apply p-0 bg-inherit
}

11
assets/js/app.js Normal file
View file

@ -0,0 +1,11 @@
import 'alpinejs'
import '../css/app.pcss'
import turbolinks from 'turbolinks'
window.hljs = require('highlightjs')
let html = document.documentElement
html.classList.remove('no-js')
html.classList.add('js')
turbolinks.start()

199
assets/js/vendor/gist-embed.js vendored Normal file
View file

@ -0,0 +1,199 @@
/*
* author: Blair Vanderhoof
* https://github.com/blairvanderhoof/gist-embed
* version 2.4
*/
(function($) {
'use strict';
function getLineNumbers(lineRangeString) {
var lineNumbers = [], range, lineNumberSections;
if (typeof lineRangeString === 'number') {
lineNumbers.push(lineRangeString);
} else {
lineNumberSections = lineRangeString.split(',');
for (var i = 0; i < lineNumberSections.length; i++) {
range = lineNumberSections[i].split('-');
if (range.length === 2) {
for (var j = parseInt(range[0], 10); j <= range[1]; j++) {
lineNumbers.push(j);
}
} else if (range.length === 1) {
lineNumbers.push(parseInt(range[0], 10));
}
}
}
return lineNumbers;
}
$.fn.gist = function() {
return this.each(function() {
var $elem = $(this),
id,
url,
file,
lines,
loading,
highlightLines,
hideFooterOption,
hideLineNumbersOption,
showLoading,
showSpinner,
data = {};
// make block level so loading text shows properly
$elem.css('display', 'block');
id = $elem.data('gist-id') || '';
file = $elem.data('gist-file');
hideFooterOption = $elem.data('gist-hide-footer') === true;
hideLineNumbersOption = $elem.data('gist-hide-line-numbers') === true;
lines = $elem.data('gist-line');
highlightLines = $elem.data('gist-highlight-line');
showSpinner = $elem.data('gist-show-spinner') === true;
if (showSpinner) {
showLoading = false;
} else {
showLoading = $elem.data('gist-show-loading') !== undefined ?
$elem.data('gist-show-loading') : true;
}
if (file) {
data.file = file;
}
// if the id doesn't exist, then ignore the code block
if (!id) {
return false;
}
url = 'https://gist.github.com/' + id + '.json';
loading = 'Loading gist ' + url + (data.file ? ', file: ' + data.file : '') + '...';
// loading
if (showLoading) {
$elem.html(loading);
}
// loading spinner
if (showSpinner) {
$elem.html('<img style="display:block;margin-left:auto;margin-right:auto" alt="' + loading + '" src="https://assets-cdn.github.com/images/spinners/octocat-spinner-32.gif">');
}
// request the json version of this gist
$.ajax({
url: url,
data: data,
dataType: 'jsonp',
timeout: 10000,
success: function(response) {
var linkTag,
head,
lineNumbers,
highlightLineNumbers,
$responseDiv;
// the html payload is in the div property
if (response && response.div) {
// github returns /assets/embed-id.css now, but let's be sure about that
if (response.stylesheet) {
// github passes down html instead of a url for the stylehsheet now
// parse off the href
if (response.stylesheet.indexOf('<link') === 0) {
response.stylesheet =
response.stylesheet
.replace(/\\/g,'')
.match(/href=\"([^\s]*)\"/)[1];
} else if (response.stylesheet.indexOf('http') !== 0) {
// add leading slash if missing
if (response.stylesheet.indexOf('/') !== 0) {
response.stylesheet = '/' + response.stylesheet;
}
response.stylesheet = 'https://gist.github.com' + response.stylesheet;
}
}
// add the stylesheet if it does not exist
if (response.stylesheet && $('link[href="' + response.stylesheet + '"]').length === 0) {
linkTag = document.createElement('link');
head = document.getElementsByTagName('head')[0];
linkTag.type = 'text/css';
linkTag.rel = 'stylesheet';
linkTag.href = response.stylesheet;
head.insertBefore(linkTag, head.firstChild);
}
// refernce to div
$responseDiv = $(response.div);
// remove id for uniqueness constraints
$responseDiv.removeAttr('id');
$elem.html('').append($responseDiv);
// option to highlight lines
if (highlightLines) {
highlightLineNumbers = getLineNumbers(highlightLines);
// we need to set the line-data td to 100% so the highlight expands the whole line
$responseDiv.find('td.line-data').css({
'width': '100%'
});
// find all .js-file-line tds (actual code lines) that match the highlightLines and add the highlight class
$responseDiv.find('.js-file-line').each(function(index) {
if ($.inArray(index + 1, highlightLineNumbers) !== -1) {
$(this).css({
'background-color': 'rgb(255, 255, 204)'
});
}
});
}
// if user provided a line param, get the line numbers based on the criteria
if (lines) {
lineNumbers = getLineNumbers(lines);
// find all trs containing code lines that don't exist in the line param
$responseDiv.find('.js-file-line').each(function(index) {
if (($.inArray(index + 1, lineNumbers)) === -1) {
$(this).parent().remove();
}
});
}
// option to remove footer
if (hideFooterOption) {
$responseDiv.find('.gist-meta').remove();
// present a uniformed border when footer is hidden
$responseDiv.find('.gist-data').css('border-bottom', '0px');
$responseDiv.find('.gist-file').css('border-bottom', '1px solid #ddd');
}
// option to remove
if (hideLineNumbersOption) {
$responseDiv.find('.js-line-number').remove();
}
} else {
$elem.html('Failed loading gist ' + url);
}
},
error: function(jqXHR, textStatus) {
$elem.html('Failed loading gist ' + url + ': ' + textStatus);
}
});
});
};
$(function() {
// find all elements containing "data-gist-id" attribute.
$('[data-gist-id]').gist();
});
})(jQuery);

1
assets/js/vendor/gist-embed.min.js vendored Normal file
View file

@ -0,0 +1 @@
(function(b){function a(d){var c=[],e,g;if(typeof d==="number"){c.push(d)}else{g=d.split(",");for(var h=0;h<g.length;h++){e=g[h].split("-");if(e.length===2){for(var f=parseInt(e[0],10);f<=e[1];f++){c.push(f)}}else{if(e.length===1){c.push(parseInt(e[0],10))}}}}return c}b.fn.gist=function(){return this.each(function(){var e=b(this),d,c,h,m,k,j,f,g,l,i={};e.css("display","block");d=e.data("gist-id")||"";h=e.data("gist-file");j=e.data("gist-hide-footer")===true;f=e.data("gist-hide-line-numbers")===true;m=e.data("gist-line");k=e.data("gist-highlight-line");l=e.data("gist-show-spinner")===true;if(l){g=false}else{g=e.data("gist-show-loading")!==undefined?e.data("gist-show-loading"):true}if(h){i.file=h}if(!d){return false}c="https://gist.github.com/"+d+".json";loading="Loading gist "+c+(i.file?", file: "+i.file:"")+"...";if(g){e.html(loading)}if(l){e.html('<img style="display:block;margin-left:auto;margin-right:auto" alt="'+loading+'" src="https://assets-cdn.github.com/images/spinners/octocat-spinner-32.gif">')}b.ajax({url:c,data:i,dataType:"jsonp",timeout:10000,success:function(p){var s,r,o,q,n;if(p&&p.div){if(p.stylesheet){if(p.stylesheet.indexOf("<link")===0){p.stylesheet=p.stylesheet.replace(/\\/g,"").match(/href=\"([^\s]*)\"/)[1]}else{if(p.stylesheet.indexOf("http")!==0){if(p.stylesheet.indexOf("/")!==0){p.stylesheet="/"+p.stylesheet}p.stylesheet="https://gist.github.com"+p.stylesheet}}}if(p.stylesheet&&b('link[href="'+p.stylesheet+'"]').length===0){s=document.createElement("link");r=document.getElementsByTagName("head")[0];s.type="text/css";s.rel="stylesheet";s.href=p.stylesheet;r.insertBefore(s,r.firstChild)}n=b(p.div);n.removeAttr("id");e.html("").append(n);if(k){q=a(k);n.find("td.line-data").css({width:"100%"});n.find(".js-file-line").each(function(t){if(b.inArray(t+1,q)!==-1){b(this).css({"background-color":"rgb(255, 255, 204)"})}})}if(m){o=a(m);n.find(".js-file-line").each(function(t){if((b.inArray(t+1,o))===-1){b(this).parent().remove()}})}if(j){n.find(".gist-meta").remove();n.find(".gist-data").css("border-bottom","0px");n.find(".gist-file").css("border-bottom","1px solid #ddd")}if(f){n.find(".js-line-number").remove()}}else{e.html("Failed loading gist "+c)}},error:function(n,o){e.html("Failed loading gist "+c+": "+o)}})})};b(function(){b("[data-gist-id]").gist()})})(jQuery);

1
assets/js/vendor/github-cards.js vendored Normal file
View file

@ -0,0 +1 @@
(function(e){var t="//cdn.jsdelivr.net/github-cards/1.0.2/";var r,i=0;var a=e.getElementsByTagName("meta");var n,d,l,c;for(r=0;r<a.length;r++){var s=a[r].getAttribute("name");var f=a[r].getAttribute("content");if(s==="gc:url"){n=f}else if(s==="gc:base"){t=f}else if(s==="gc:client-id"){d=f}else if(s==="gc:client-secret"){l=f}else if(s==="gc:theme"){c=f}}function u(t){if(e.querySelectorAll){return e.querySelectorAll("."+t)}var i=e.getElementsByTagName("div");var a=[];for(r=0;r<i.length;r++){if(~i[r].className.split(" ").indexOf(t)){a.push(i[r])}}return a}function g(e,t){return e.getAttribute("data-"+t)}function h(e){if(window.addEventListener){window.addEventListener("message",function(t){if(e.id===t.data.sender){e.height=t.data.height}},false)}}function v(r,a){a=a||n;if(!a){var s=g(r,"theme")||c||"default";a=t+"cards/"+s+".html"}var f=g(r,"user");var u=g(r,"repo");var v=g(r,"github");if(v){v=v.split("/");if(v.length&&!f){f=v[0];u=u||v[1]}}if(!f){return}i+=1;var o=g(r,"width");var m=g(r,"height");var b=g(r,"target");var w=g(r,"client-id")||d;var p=g(r,"client-secret")||l;var A="ghcard-"+f+"-"+i;var y=e.createElement("iframe");y.setAttribute("id",A);y.setAttribute("frameborder",0);y.setAttribute("scrolling",0);y.setAttribute("allowtransparency",true);var E=a+"?user="+f+"&identity="+A;if(u){E+="&repo="+u}if(b){E+="&target="+b}if(w&&p){E+="&client_id="+w+"&client_secret="+p}y.src=E;y.width=o||Math.min(r.parentNode.clientWidth||400,400);if(m){y.height=m}h(y);r.parentNode.replaceChild(y,r);return y}var o=u("github-card");for(r=0;r<o.length;r++){v(o[r])}if(window.githubCard){window.githubCard.render=v}})(document);

10
assets/js/vendor/tweets.js vendored Normal file

File diff suppressed because one or more lines are too long

66
composer.json Normal file
View file

@ -0,0 +1,66 @@
{
"name": "opdavies/oliverdavies.uk",
"description": "Oliver Davies personal website",
"type": "project",
"keywords": ["sculpin"],
"homepage": "https://github.com/opdavies/oliverdavies.uk",
"license": "MIT",
"authors": [
{
"name": "Oliver Davies",
"homepage": "https://www.oliverdavies.uk",
"role": "Developer"
}
],
"scripts": {
"dev": "@development",
"development": "sculpin generate --clean --no-interaction",
"prod": "@production",
"production": "sculpin generate --clean --no-interaction --env prod",
"test": [
"@test-phpcs",
"@test-phpstan",
"@test-phpunit"
],
"test-phpcs": "php-cs-fixer fix --dry-run",
"test-phpstan": "phpstan analyze",
"test-phpunit": "phpunit",
"watch": [
"Composer\\Config::disableProcessTimeout",
"sculpin generate --clean --no-interaction --watch --server"
]
},
"require": {
"php": "^7.2",
"dflydev/embedded-composer": "^1.0@dev",
"friendsofphp/php-cs-fixer": "^2.14",
"opdavies/sculpin-gist-embed-bundle": "^0.1",
"opdavies/sculpin-twig-markdown-bundle": "^0.1",
"phpstan/phpstan": "^0.11.8",
"sculpin/sculpin": "^3.0",
"spatie/string": "^2.2",
"tightenco/collect": "^6.1",
"wikimedia/composer-merge-plugin": "^1.4"
},
"require-dev": {
"opdavies/sculpin-content-generator-bundle": "@stable",
"phpstan/phpstan-deprecation-rules": "^0.11.2",
"phpunit/phpunit": "^8.4"
},
"config": {
"platform": {
"php": "7.2"
},
"sort-packages": true
},
"autoload": {
"psr-4": {
"App\\": "src"
}
},
"autoload-dev": {
"psr-4": {
"App\\Tests\\": "tests"
}
}
}

6654
composer.lock generated Normal file

File diff suppressed because it is too large Load diff

135
generators/blog-post.php Normal file
View file

@ -0,0 +1,135 @@
<?php
use Spatie\String\Str;
use Symfony\Component\Console\Application;
use Symfony\Component\Console\Command\Command;
use Symfony\Component\Console\Input\InputArgument;
use Symfony\Component\Console\Input\InputInterface;
use Symfony\Component\Console\Output\OutputInterface;
use Symfony\Component\Console\Question\Question;
use Symfony\Component\Console\Style\SymfonyStyle;
require_once __DIR__.'/../vendor/autoload.php';
$application = new Application();
$application->addCommands([
new class extends Command
{
/**
* {@inheritdoc}
*/
protected static $defaultName = 'main';
/**
* {@inheritdoc}
*/
protected function configure()
{
$this->addArgument('title', InputArgument::OPTIONAL);
$this->addArgument('excerpt', InputArgument::OPTIONAL);
$this->addArgument('tags', InputArgument::IS_ARRAY);
}
/**
* {@inheritdoc}
*/
protected function interact(InputInterface $input, OutputInterface $output)
{
$io = new SymfonyStyle($input, $output);
if (!$input->getArgument('title')) {
$input->setArgument('title', $io->askQuestion(
new Question('The post title')
));
}
if (!$input->getArgument('excerpt')) {
$input->setArgument('excerpt', $io->askQuestion(
new Question('The post excerpt')
));
}
$io->writeln("\nEnter any tags for the post.\nPress <info>enter</info> to <info>continue</info>.\n");
$tags = [];
while (true) {
$tag = $io->askQuestion(
new Question('Enter a tag')
);
if (empty($tag)) {
break;
}
$tags[] = $tag;
}
$input->setArgument('tags', $tags);
}
/**
* {@inheritdoc}
*/
protected function execute(InputInterface $input, OutputInterface $output)
{
$io = new SymfonyStyle($input, $output);
$title = $input->getArgument('title');
if (!$title) {
throw new \RuntimeException('No title');
}
$excerpt = $input->getArgument('excerpt') ?? $title;
$slug = (new Str($title))->slugify();
$tags = '[' . implode(', ', $input->getArgument('tags')) . ']';
$date = (new \DateTime())->format('Y-m-d');
$contents = $this->generateFileFromStub(
$title,
$excerpt,
$tags,
$date
);
$this->writeFile($slug, $contents);
$this->createImagesDirectory($slug);
$io->listing([
"{$slug}.md"
]);
}
private function generateFileFromStub(...$args): string
{
[$title, $excerpt, $tags, $date] = $args;
return <<<EOF
---
title: $title
excerpt: $excerpt
date: $date
tags: $tags
draft: true
---
TODO.
EOF;
}
private function writeFile(string $slug, string $contents): void
{
file_put_contents("source/_posts/{$slug}.md", $contents);
}
private function createImagesDirectory(string $slug): void
{
mkdir("source/images/{$slug}");
}
}
]);
$application->setDefaultCommand('main');
$application->run();

11
netlify.toml Normal file
View file

@ -0,0 +1,11 @@
[build]
command = """
composer test && \
npm run lint --fix-dry-run && \
npm run production && \
composer run production
"""
publish = "output_prod"
[build.environment]
PHP_VERSION = "7.2"

9495
package-lock.json generated Normal file

File diff suppressed because it is too large Load diff

40
package.json Normal file
View file

@ -0,0 +1,40 @@
{
"private": true,
"scripts": {
"dev": "npm run development",
"development": "encore dev",
"lint": "eslint --ext .js,.vue assets/js/app.js",
"prod": "npm run production",
"production": "encore production --progress",
"watch": "encore dev --watch"
},
"dependencies": {
"@symfony/webpack-encore": "^0.28.0",
"alpinejs": "^1.8.2",
"highlightjs": "^9.16.2",
"postcss-import": "^12.0.1",
"postcss-nested": "^4.2.1",
"prettier": "^1.19.1",
"tailwindcss": "^1.1.3",
"tailwindcss-interaction-variants": "^2.2.0",
"tailwindcss-skip-link": "^1.0.1",
"tailwindcss-spaced-items": "^0.1.0",
"tailwindcss-visuallyhidden": "^1.0.2",
"turbolinks": "^5.2.0"
},
"devDependencies": {
"eslint": "^5.15.3",
"eslint-config-standard": "^12.0.0",
"eslint-plugin-import": "^2.16.0",
"eslint-plugin-node": "^9.1.0",
"eslint-plugin-promise": "^4.0.1",
"eslint-plugin-standard": "^4.0.0",
"eslint-plugin-vue": "^5.2.2",
"glob-all": "^3.1.0",
"postcss-loader": "^3.0.0",
"purgecss-webpack-plugin": "^1.6.0"
},
"engines": {
"yarn": "YARN NO LONGER USED - use npm instead."
}
}

6
phpstan.neon Normal file
View file

@ -0,0 +1,6 @@
parameters:
level: 7
paths:
- src
includes:
- vendor/phpstan/phpstan-deprecation-rules/rules.neon

13
phpunit.xml.dist Normal file
View file

@ -0,0 +1,13 @@
<?xml version="1.0" encoding="UTF-8"?>
<phpunit bootstrap="./vendor/autoload.php"
colors="true"
convertErrorsToExceptions="true"
convertNoticesToExceptions="true"
convertWarningsToExceptions="true"
stopOnFailure="true">
<testsuites>
<testsuite name="Talks">
<directory suffix="Test.php">app/tests</directory>
</testsuite>
</testsuites>
</phpunit>

8
postcss.config.js Normal file
View file

@ -0,0 +1,8 @@
module.exports = {
plugins: [
require('postcss-import'),
require('tailwindcss'),
require('postcss-nested'),
require('autoprefixer')
]
}

10
prettier.config.js Normal file
View file

@ -0,0 +1,10 @@
module.exports = {
endOfLine: 'lf',
printWidth: 80,
proseWrap: 'always',
quoteProps: 'as-needed',
singleQuote: true,
tabWidth: 2,
trailingComma: 'all',
useTabs: false,
}

9
purgecss.config.js Normal file
View file

@ -0,0 +1,9 @@
let glob = require('glob-all')
module.exports = {
defaultExtractor: content => content.match(/[\w-/:]+(?<!:)/g) || [],
paths: () => glob.sync([
'source/**/*.{md,twig}'
]),
whitelistPatterns: [/(code|kbd|pre|samp)/, /hljs/, /language/]
}

2
source/_headers Normal file
View file

@ -0,0 +1,2 @@
/feed
Content-Type: application/xml

View file

@ -0,0 +1,35 @@
<!DOCTYPE html>
<html lang="en-GB" class="no-js">
<head>
<title>{% if page.title is defined and page.url != '//' %}{{ page.title }} | {% endif %}{{ site.title }} - {{ site.subtitle }}</title>
{% include 'meta' %}
{% block metas %}
<meta name="twitter:site" content="@{{ site.twitter.user }}">
<meta name="twitter:title" content="{{ page.title }}">
<meta name="twitter:creator" content="@{{ site.twitter.user }}">
{% endblock %}
<link rel="stylesheet" href="{{ asset('build/app.css') }}">
{% block stylesheets %}{% endblock %}
{% for size in site.apple_touch_icon_sizes %}
<link rel="apple-touch-icon" href="{{ site.favicon.url }}?s={{ size }}" sizes="{{ size }}x{{ size }}">
{% endfor %}
{% for size in site.favicon_sizes %}
<link rel="icon" href="{{ site.favicon.url }}?s={{ size }}" sizes="{{ size }}x{{ size }}">
{% endfor %}
</head>
<body class="antialiased font-sans text-gray-800 leading-relaxed">
<div class="min-h-screen flex flex-col">
{% block body %}{% endblock %}
</div>
{% if site.google_analytics.id %}
<script>(function(i,s,o,g,r,a,m){i['GoogleAnalyticsObject']=r;i[r]=i[r]||function(){ (i[r].q=i[r].q||[]).push(arguments)},i[r].l=1*new Date();a=s.createElement(o),m=s.getElementsByTagName(o)[0];a.async=1;a.src=g;m.parentNode.insertBefore(a,m) })(window,document,'script','//www.google-analytics.com/analytics.js','ga'); ga('create', '{{ site.google_analytics.id }}', 'auto'); ga('send', 'pageview');</script>
{% endif %}
<script src="{{ asset('build/app.js') }}"></script>
{% block scripts %}{% endblock %}
</body>
</html>

View file

@ -0,0 +1,33 @@
{% extends 'app' %}
{% block body %}
{% include 'layout/navbar' %}
<div class="mt-10 container">
<main id="main-content" class="flex-1 wrap {{ page.layout == 'front' ? 'is-wide' : '' }}">
{# {% if page.layout in ['post', 'talk'] %}
{% include 'site-message' %}
{% endif %} #}
{% block page_title_wrapper %}
<h1 class="leading-tight mb-4">
{% block page_title %}{{ page.title }}{% endblock %}
</h1>
{% endblock %}
{% block content_wrapper %}
{% block content %}{% endblock %}
{% endblock %}
</main>
{% include 'layout/footer' %}
</div>
{% endblock %}
{% block scripts %}
{% if page.has_tweets or page.type == 'tweet' %}
<script async src="https://platform.twitter.com/widgets.js" charset="utf-8"></script>
{% endif %}
<script>hljs.initHighlightingOnLoad();</script>
{% endblock %}

View file

@ -0,0 +1,17 @@
{% extends 'default' %}
{% block content_wrapper %}
<div class="md:flex -mx-6">
<div class="wrap md:flex-1 px-6 mb-12 md:mb-0">
<div class="markup spaced-y-4 mb-8">
{% block content %}{% endblock %}
</div>
{% include 'about/availability' %}
</div>
<div class="w-full md:w-2/5 lg:w-1/3 px-6">
{% include 'about/badges' %}
</div>
</div>
{% endblock %}

View file

@ -0,0 +1,12 @@
{% macro talkEventName(event) %}
{% if event.url %}
<a href="{{ event.url }}">{{ event.name }}</a>
{% else %}
{{ event.name }}
{% endif %}
{% endmacro %}
{% macro talkEventLocation(event) %}
{{ event.location ? 'in ' ~ event.location }}
{{ event.remote ? ' (Remote)' }}
{% endmacro %}

View file

@ -0,0 +1,7 @@
{% extends 'default' %}
{% block content_wrapper %}
<div>
{% block content %}{% endblock %}
</div>
{% endblock %}

View file

@ -0,0 +1,26 @@
{% extends 'default' %}
{% block page_title_wrapper %}{% endblock %}
{% block metas %}
{{ parent() }}
<meta name="og:description" content="{{ page.excerpt }}">
<meta name="twitter:description" content="{{ page.excerpt }}">
{% endblock %}
{% block content_wrapper %}
{% include 'post/header' %}
{% include 'post/intro-image' %}
<div class="markup post mb-6">
{% include 'post/old-post-message' %}
{% block content %}{% endblock %}
</div>
<div class="mb-6">
{% include 'post/questions-comments' %}
{% include 'post/tags' %}
</div>
{% include 'post/about-author' %}
{% endblock %}

View file

@ -0,0 +1,31 @@
{% extends 'default' %}
{% block metas %}
{{ parent() }}
<meta name="og:description" content="{{ page.description }}">
<meta name="twitter:card" content="summary_large_image">
<meta name="twitter:description" content="{{ page.description }}">
{% endblock %}
{% block content_wrapper %}
<div class="spaced-y-8">
<div class="markup spaced-y-6">
{% block content %}{% endblock %}
<section>
<h2 class="sr-only">Give me feedback</h2>
<p>
<strong>Want to give me feedback for this talk?</strong>
Im <a href="{{ site.twitter.url }}" title="Leave me feedback on Twitter">@{{ site.twitter.user }}</a> on Twitter or <a href="/contact">send me an email</a>.
</p>
</section>
</div>
{% include 'talk/slides' %}
{% include 'talk/video' %}
{% include 'talk/tweets' %}
{% include 'talk/events' with { events: get_events_for_talk(page, site.events) } only %}
</div>
{% endblock %}

7
source/_pages/404.md Normal file
View file

@ -0,0 +1,7 @@
---
title: Page Not Found
permalink: /404.html
use: [posts]
---
Please [contact me](/contact/) and let me know.

39
source/_pages/about.md Normal file
View file

@ -0,0 +1,39 @@
---
layout: front
title: About Me
meta:
og:
title:
'Oliver Davies - Full Stack Developer, System Administrator, PHP and
Drupal specialist'
description:
'The personal website and blog of Oliver Davies, a Full Stack Developer
and System Administrator from Wales, UK.'
type: website
permalink: /
---
<div class="mb-4 w-32"><img src="/images/me-precedent.jpg" alt="Picture of Oliver" class="rounded-full border border-gray"/></div>
Hi, I'm Oliver Davies (aka [opdavies](https://www.google.com/#q=opdavies)). Im
a {{ site.work.role }} at
[{{site.companies[site.work.company].name}}]({{site.companies[site.work.company].url}})
and a part-time freelance Web Developer, based in Wales, UK.
Ive been a Developer since 2007 and specialise in using Drupal, Symfony and
Vue.js, though I also use other technologies including Laravel and Sculpin. I
use Ansible for server provisioning and application deployments.
Im an [Acquia certified](https://certification.acquia.com/user/1647756) Drupal
8 Grand Master, and Webmaster and Documentation Maintainer on
[Drupal.org](https://www.drupal.org). I was previously a Developer for the
[{{site.companies.drupal_association.name}}]({{site.companies.drupal_association.url}}).
I regularly [give talks](/talks) at user groups and conferences, and am an
organiser of the
[{{site.events.php_south_wales.name}}]({{site.events.php_south_wales.url}}) user
group.
I enjoy contributing to open source, and maintain a variety of different
projects. You can see these on my [Drupal.org]({{site.drupalorg.url}}) and
[GitHub]({{site.github.url}}) accounts.

View file

@ -0,0 +1,11 @@
---
title: Accessibility
use: [posts]
---
# Accessibility
I have made as much effort as possible to make this website accessible to all
users.
If you have any suggestions to improve the site, please [contact me](/contact/).

View file

@ -0,0 +1,14 @@
---
title: Company Information
meta:
description: 'Company information for Oliver Davies Ltd.'
use: [posts]
---
# Company Information
Company name : Oliver Davies Ltd (previously Oliver Davies Web Development Ltd)
Registered address : 3 Westfield Close, Caerleon, Newport, NP18 3ED
Company number : 8017706

View file

@ -0,0 +1,8 @@
---
title: Thanks!
permalink: contact/thanks/
use: [posts]
---
Your email has been sent. You should receive a response within the next working
day.

View file

@ -0,0 +1,42 @@
---
title: Contact
use: [posts]
honeypot_field: Qr4W7oB25C
---
{% block content %}
<div class="mt-2 mb-6">
<p>To send me an email, complete the form below.</p>
</div>
<form name="contact" method="POST" netlify-honeypot="{{ page.honeypot_field }}" data-netlify="true" class="spaced-y-4">
<div class="spaced-y-1">
<label for="name" class="block">Name</label>
<input type="text" class="w-full p-2 border border--grey" id="name" name="name" required />
</div>
<div class="spaced-y-1">
<label for="email" class="block">Email</label>
<input type="email" class="w-full p-2 border border--grey" id="email" name="email" required />
</div>
<div class="spaced-y-1">
<label for="subject" class="block">Subject</label>
<input type="text" class="w-full p-2 border border--grey" id="subject" name="subject" required />
</div>
<div class="spaced-y-1">
<label for="message" class="block">Message</label>
<textarea id="message" class="w-full p-2 border border--grey" rows="5" name="message" required></textarea>
</div>
<p class="hidden">
<label>Dont fill this out if you're human: <input name="{{ page.honeypot_field }}" /></label>
</p>
<div>
<button class="button" type="submit">Send email</button>
</div>
<input type="hidden" name="_next" value="{{ site.url }}/contact/thanks" />
</form>
{% endblock %}

28
source/_pages/dev.md Normal file
View file

@ -0,0 +1,28 @@
---
title: Developing this Website (WIP)
---
This site is built with [Sculpin][], a static site generator written in PHP,
that generates a static HTML website from Markdown files and Twig templates. You
can see the [source code on GitHub].
## Extending Sculpin
- Custom Twig extensions
- https://github.com/opdavies/sculpin-twig-markdown-bundle
- https://github.com/opdavies/sculpin-gist-embed-bundle
- https://github.com/opdavies/sculpin-content-generator-bundle
## Front End
On the front-end, I have used [PostCSS][] rather than Sass or Less, and
[Tailwind CSS] for all of the styling, and some [Vue.js][] for the navbar and
toggling the navigation menu on mobile. These are compiled with [Webpack
Encore][] - a wrapper around Webpack, provided by Symfony.
[postcss]: https://postcss.org
[sculpin]: https://sculpin.io
[source code on github]: https://github.com/opdavies/oliverdavies.uk
[tailwind css]: https://tailwindcss.com
[vue.js]: https://vuejs.org
[webpack encore]: https://github.com/symfony/webpack-encore

View file

@ -0,0 +1,168 @@
---
title: Open Source
projects:
drupal:
- name: Accessibility (a11y) Checklist
description: Similar to the SEO Checklist and QA Checklist modules, this module provides a checklist of accessibilty-related modules and tasks to perform on a Drupal site.
url: https://www.drupal.org/project/a11y_checklist
versions: [7]
- name: Block ARIA Landmark Roles
description: Inspired by Block Class, this module adds additional elements to the block configuration forms that allow users to assign a ARIA landmark role to a block.
url: https://www.drupal.org/project/block_aria_landmark_roles
versions: [7]
- name: Breadcrumbs by Path
description: A light-weight module which simply builds breadcrumb trails based on a URL alias.
url: https://www.drupal.org/project/breadcrumbs_by_path
versions: [7]
- name: Collection class
description: Integrates Laravels Collection class into Drupal 7.
url: https://www.drupal.org/project/collection_class
versions: [7]
- name: Comment Hide Subject
description: Hides the comment subject if the "Allow comment title" checkbox is unchecked for that node type.
url: https://www.drupal.org/project/comment_hide_subject
versions: [7]
- name: Commerce Cart Empty Paths
description: This module allows site administrators to define multiple paths, and when a user visits a non-declared page, their shopping cart is emptied.
url: https://www.drupal.org/project/commerce_cart_empty_paths
versions: [7]
- name: Copyright Block
description: Creates a block that allows you to configure a copyright message that automatically updates using the current year from the server that your site is hosted on.
url: https://www.drupal.org/project/copyright_block
versions: [7, 8]
- name: Image Style Class
description: Adds classes onto each rendered image showing the image style name.
url: https://www.drupal.org/project/image_style_class
versions: [7]
- name: Mapify
description: A module to make the implementation of mapify.js into Drupal 7 relatively simple.
url: https://www.drupal.org/project/mapify
versions: [7]
- name: Node Comment Block
description: This module moves the comments for a node into a moveable block.
url: https://www.drupal.org/project/node_comment_block
versions: [7]
- name: Null User
description: Adds a NullUser class for simpler code with less conditions.
url: https://www.drupal.org/project/null_user
versions: [8]
- name: Override Node Options
description: Allows permissions to be set to each field within the Authoring information and Publishing options field sets on the node form.
url: https://www.drupal.org/project/override_node_options
versions: [7, 8]
- name: Pathauto Menu Link
description: Forces an update of the Pathauto-generated path when a menu link item has been updated. Useful if you use parent menu links to generate paths.
url: https://www.drupal.org/project/pathauto_menu_link
versions: [7, 8]
- name: Private Message Queue
description: Adds the ability to queue private messages for sending.
url: https://www.drupal.org/project/private_message_queue
versions: [8]
- name: 'Rules Block/Unblock User'
description: Adds rules events, as well as some default rules, for when a user account is blocked or unblocked.
url: https://www.drupal.org/project/rules_block_user
versions: [7]
- name: SpeakerDeck Field
description: Adds a field for embedding content from SpeakerDeck.
url: https://www.drupal.org/project/speakerdeck_field
versions: [8]
- name: System User
description: Adds the ability to identify and retrieve system users.
url: https://www.drupal.org/project/system_user
versions: [7, 8]
- name: Toggle Optional Fields
description: Creates a simplified node form by allowing for the hiding and toggling of optional fields.
url: https://www.drupal.org/project/toggle_optional_fields
versions: [7]
- name: Webform ARIA
description: Adds ARIA support to forms created using the Webform module.
url: https://www.drupal.org/project/webform_aria
versions: [7]
- name: WP Blog Migrate
description: Convert your existing Drupal blog into the WP Blog module by re-assigning the content type for existing nodes and moving any existing tags into the WP Blog taxonomy vocabulary.
url: https://www.drupal.org/project/wp_blog_migrate
versions: [7]
sculpin:
- name: oliverdavies.uk
description: The source code for this website, which is built with Sculpin.
url: https://github.com/opdavies/oliverdavies.uk
- name: Sculpin Content Generator Bundle
description: Provides new Sculpin commands for generating new content.
url: https://github.com/opdavies/sculpin-content-generator-bundle
- name: Sculpin Gist Bundle
description: Allows for embedding GitHub Gists into a Sculpin site.
url: https://github.com/opdavies/sculpin-gist-embed-bundle
- name: Sculpin Skeleton
description: A skeleton project for the Sculpin static site generator.
url: https://github.com/opdavies/sculpin-skeleton
- name: Sculpin Twig Markdown Bundle
description: Enables rendering content from markdown, using Sculpins core markdown parser.
url: https://github.com/opdavies/sculpin-twig-markdown-bundle
- name: Sculpin Twig Sort by Field Bundle
description: Enables sorting an array by a certain field on each item.
url: https://github.com/opdavies/sculpin-twig-sort-by-field-bundle
php:
- name: Drupal Meetups Twitterbot
description: A Twitter bot that retweets posts about Drupal meetups.
url: https://github.com/opdavies/drupal-meetups-twitterbot
- name: Drupal VM CLI
description: A command line tool for Drupal VM.
url: https://github.com/opdavies/drupal-vm-cli
active: false
- name: Gmail Filter Builder
description: Allows you to define Gmail filters in PHP using a fluent API, and then generate XML that you can import into Gmail's filter settings.
url: https://github.com/opdavies/gmail-filter-builder
---
<p>I have written, open-sourced, and maintain a number of Drupal modules, Sculpin bundles and PHP projects - as well as the source code for this website! Here is some information about each project and a link to its project page.</p>
<div class="mb-4">
<h2>Drupal</h2>
{% include 'opensource/projects' with {
projects: page.projects.drupal
} %}
</div>
<div class="mb-4">
<h2>Sculpin</h2>
{% include 'opensource/projects' with {
projects: page.projects.sculpin
} %}
</div>
<div>
<h2>PHP</h2>
{% include 'opensource/projects' with {
projects: page.projects.php
} %}
</div>

View file

@ -0,0 +1,99 @@
---
title: Podcasts
podcasts:
howtocodewell:
name: How to Code Well
url: https://howtocodewell.fm
talking_drupal:
name: Talking Drupal
url: http://talkingdrupal.com
thatpodcast:
name: That Podcast
url: https://thatpodcast.io
episodes:
- title: 'Episode #175 - Automated Testing'
description: I joined the Talking Drupal team to discuss automated testing.
podcast: talking_drupal
date: 2018-09-05
url: http://talkingdrupal.com/175
audio: true
- title: 'Episode #204 - A Few Things'
description: I joined the Talking Drupal team again, where we discussed Drupal updates, conferences and more.
podcast: talking_drupal
date: 2019-03-25
url: http://talkingdrupal.com/204
audio: true
- title: What's new in Drupal 8+
description: Talking about Drupal, open source, Drupal 7 vs Drupal 8, module development, testing and more.
podcast: howtocodewell
date: 2019-04-12
url: https://howtocodewell.fm/episode/15-whats-new-in-drupal-8-plus-oliver-davies-interview
audio: true
video: true
- title: 'Episode 60 - The One Where We Talk Twig, Drupal, and Sculpin'
description: I joined Beau and Dave to talk about various topics including Drupal, the Sculpin static site generator, Twig, Tailwind CSS and Symfony.
podcast: thatpodcast
date: 2019-07-01
url: https://thatpodcast.io/episodes/episode-60-the-one-where-we-talk-twig-drupal-and-sculpin-with-oliver-davies
audio: true
- title: Static Site Generators
description: |
Talking again with Peter Fisher, this time about static site generators. We talk about what they are, when you should and shouldnt use them, and how to use them with a content management system like Drupal.
podcast: howtocodewell
date: 2019-07-19
url: https://howtocodewell.fm/episode/29-what-are-static-site-generators-oliver-davies
audio: true
video: true
---
{% macro episodeTitle(podcast, episode) -%}
{{ podcast.name }}: {{ episode.title }}
{%- endmacro %}
{% import _self as helpers %}
<header class="markup">
<p class="text-lg">As well as <a href="{{ site.menus.main.articles.href }}">writing posts</a> and <a href="{{ site.menus.main.talks.href }}">giving talks</a>, I also enjoy being on podcasts and speaking about interesting topics.</p>
<p class="text-lg">Here are the podcasts that Ive been on, including <a href="{{ page.podcasts.talking_drupal.url }}">{{ page.podcasts.talking_drupal.name }}</a> and <a href="{{ page.podcasts.howtocodewell.url }}">{{ page.podcasts.howtocodewell.name }}</a>.</p>
</header>
<div class="mt-10 spaced-y-10">
{% for episode in page.episodes|reverse %}
{% set podcast = page.podcasts[episode.podcast] %}
<article>
<h2 class="text-lg">
{% if episode.url %}
<a href="{{ episode.url }}" class="text-inherit" tabindex="-1">
{{ helpers.episodeTitle(podcast, episode) }}
</a>
{% else %}
{{ helpers.episodeTitle(podcast, episode) }}
{% endif %}
</h2>
<time class="text-sm text-gray-800 block mt-px mb-2" datetime="{{ episode.date|date('Y-m-d') }}">
{{ episode.date|date('jS F Y') }}
</time>
<div class="markup">
{{ episode.description|markdown }}
</div>
{% if episode.url %}
<a href="{{ episode.url }}" class="inline-block mt-2 text-sm text-gray-600 hover:text-gray-800 focus:text-gray-800">
{% if episode.video %}
Watch {{ episode.video and episode.audio ? 'or listen to' }}
{% elseif episode.audio %}
Listen to
{% endif %} this
<span class="visuallyhidden">{{ podcast.name }}</span>
episode &rarr;
</a>
{% endif %}
</article>
{% endfor %}
</div>

View file

@ -0,0 +1,57 @@
---
title: Projects
projects:
- title: Rebuilding Acquia
description: A clone of Acquias hosting dashboard, built with Vue.js and Tailwind CSS.
url: https://github.com/opdavies/rebuilding-acquia
- title: Rebuilding Bartik
description: A clone of Bartik (Drupals default theme), built with Vue.js and Tailwind CSS.
url: https://github.com/opdavies/rebuilding-bartik
- title: Joind.in Winner Picker
description: A Symfony 4 application that determines a randomly selected winner from a section of feedback left on Joind.in. Developed on behalf of the PHP South West (PHPSW) user group.
url: https://github.com/opdavies/joindin-winner-picker-new
- title: Drupal.org API library
description: A PHP library for interacting with the Drupal.org API.
url: https://github.com/opdavies/drupalorg-api-php
- title: Drupal Meetups Twitterbot
description: A Symfony 4 application for retweeting tweets about Drupal meetups.
url: https://github.com/opdavies/sculpin-skeleton
- title: Gmail Filter Builder
description: A library for writing Gmail filters in PHP, then exporting them to importable XML.
url: https://github.com/opdavies/gmail-filter-builder
- title: Sculpin Skeleton
description: A skeleton project for the Sculpin static site generator.
url: https://github.com/opdavies/sculpin-skeleton
---
<div class="spaced-y-4">
<p class="lead">Here are some of the open source projects that Ive written or currently maintain.</p>
<p class="lead">For the full list, see my <a href="{{ site.github.url }}">GitHub</a> and <a href="{{ site.drupalorg.url_new }}">Drupal.org</a> profiles.</p>
</div>
<div class="mt-8 spaced-y-10">
{% for project in page.projects %}
<article>
<h2 class="text-lg">
<a class="text-inherit" href="{{ project.url }}" tabindex="-1">
{{ project.title }}
</a>
</h2>
<p class="mt-1">{{ project.description }}</p>
<p class="mt-2 text-sm">
<a class="text-gray-600 hover:text-black" href="{{ project.url }}">
Find out more
<span class="visuallyhidden">about {{ project.title }}</span>
&rarr;
</a>
</p>
</article>
{% endfor %}
</div>

View file

@ -0,0 +1,47 @@
---
---
<div class="markup" markdown="1">
# Speaker Info
## Bio
[Oliver Davies][website] ([@opdavies][twitter]) has been building websites since
2007, and speaking at meetups and conferences since 2012. He is a Full Stack
Developer and an Acquia certified Drupal Grand Master, who also has experience
developing with Symfony, Laravel, Sculpin and Vue.js, as well as with DevOps and
systems administration.
He is a {{ site.work.role }} at
[{{ site.companies[site.work.company].name }}][work], a Drupal core contributor
and mentor, and an open source and contribution advocate.
He regularly blogs and gives talks on various topics, maintains and contributes
to various open source projects, and co-organises the PHP South Wales user
group.
[twitter]: {{site.twitter.url}}
[website]: {{site.url}}
[work]: {{site.companies[site.work.company].url}}
## Photos
- <https://www.dropbox.com/s/den3ww3lpve08fa/precedent_thumb.jpg>
- <https://www.dropbox.com/s/etrahx3hq2vpqcb/phpnw17.png>
## Some Events Ive Spoken At
- BlueConf 2019
- DrupalCamp Brighton 2015
- DrupalCamp Bristol 2016
- DrupalCamp Dublin 2017
- DrupalCamp London (2014, 2015, 2016, 2017, 2019)
- DrupalCamp North 2015
- DrupalCon Amsterdam 2019
- Nomad PHP
- PHP North West 2017 (10 year anniversary)
- PHP South Coast 2016
- PHP UK Conference 2018
- WordCamp Bristol 2019
</div>

18
source/_pages/stream.md Normal file
View file

@ -0,0 +1,18 @@
---
title: Live Streaming
---
I like try and do some live coding when I can, whether Im working on a side
project, my own website or some open source code. You can find my [stream link
on YouTube][0], or view some previous streams below:
## Stream Playlists
- [Miscellaneous coding live streams][1] {# - [Building the PHP South Wales
website][2] #} {# - [Using PHP to generate Gmail Filter XML with the Gmail
Filter Builder][3] #}
[0]: {{site.youtube.stream.url}}
[1]: https://www.youtube.com/playlist?list=PLHn41Ay7w7kcWbjrYaiqXlfrqi_teTJE8
[2]: https://www.youtube.com/playlist?list=PLHn41Ay7w7keUxBa-6TNn0_xz27ZfLD5f
[3]: https://www.youtube.com/playlist?list=PLHn41Ay7w7keRp47rXEx9his-oA8kk4-v

View file

@ -0,0 +1,47 @@
---
title: Talks
meta:
description: 'Information about previous and upcoming talks that Oliver has presented at conferences and user groups'
use: [talks]
talks:
- title: 'Drupal and the LDAP module'
description: A review and demonstration of some of the recent single sign-on work that I did using Drupals LDAP module.
events:
- event: swdug
date: 2013-07-10
- title: 'About the Drupal Association'
description: An impromptu talk about what the Drupal Association is, and what work Ive been doing since I joined the Association staff.
events:
- event: swdug
date: 2014-08-19
- title: 'Automated testing and Test Driven Development in Drupal 8'
description: A workshop that I gave about automated testing and test driven development in Drupal 8.
type: Workshop
events:
- event: drupal_bristol
date: 2018-06-27
- event: drupalcamp_london_20
date: 2020-03-13
---
{% block content %}
{% set talks = page.talks|merge(data.talks) %}
<header>
<p class="lead">
After giving my first talk in September 2012, I have now given {{ get_past_talk_count(talks) }} presentations at various conferences and meetups,
on topics including PHP, Drupal, Git, CSS and systems administration.
</p>
</header>
<div class="spaced-y-10 mt-6">
{% include 'talks/upcoming' with {
talks: get_upcoming_talks(talks),
} only %}
{% include 'talks/past' with {
talks: get_past_talks(talks),
} only %}
</div>
{% endblock %}

8
source/_pages/terms.md Normal file
View file

@ -0,0 +1,8 @@
---
title: Development Terms
use: [posts]
---
# Development Terms
TODO

View file

@ -0,0 +1,61 @@
---
title: 'Test Driven Drupal: The Book'
mailchimp_url: 'https://oliverdavi.us18.list-manage.com/subscribe/post?u=b4ac8dd177796d37b93f9c285&amp;id=033c84e0d5'
contact_email: 'oliver@testdrivendrupal.com'
---
{% block content %}
<!-- prettier-ignore -->
<div class="markup spaced-y-4 mb-6" markdown="1">
Having [given talks][1] and [workshops][workshop], been a guest on podcasts and [written articles][0] about automated testing in Drupal, Im currently in the planning phase of a book and potentially some accompanying screencasts about it, focussing on Drupal 8.
Im still thinking about what use-cases to cover and examples to include, but
here are some of the things Im considering:
- What things to test, and what not to test
- The different types of available tests, and when to use each
- How to write testable code
- What happens when I run a test?
- How to run tests in the Drupal UI
- How to run tests with the `run-tests.sh` script
- How to install, configure and run tests with PHPUnit in Drupal 8
- Viewing HTML from run tests
- How to write your first test
- Debugging tests
- How to organise your test files
- Selecting the right base class and using test traits
- Writing your own base test classes, traits and assertions
- Managing dependencies for your tests (fields, configuration)
- Creating users, checking access with roles and permissions
- Creating pages and blocks with Views and testing the output
- Creating pages with routes and controllers and testing the output
- Testing custom plugins
- Testing queuing items and processing queues
- Testing sending emails
- Testing custom Twig filters and functions
<!-- - Testing data migrations -->
<!-- - Building and testing APIs using RESTful web services module -->
- Running tests as part of your continuous integration pipeline
Ill most likely be publishing it via Leanpub, and will be sending free
chapters, early-bird discounts and links to screencasts and blog posts as I
write the book to subscribers of the mailing list.
If you have questions or would like to suggest something for me to include in
the book, please <a href="mailto:{{ page.contact_email }}">contact me</a>.
**Enter your email address to subscribe to the Test Driven Drupal mailing list
and be notified of any updates.**
</div>
{% include 'pages/book/signup-form' %}
<!-- prettier-ignore -->
{% endblock %}
[0]: /articles/tags/testing
[1]: /talks/tdd-test-driven-drupal
[2]: /contact
[workshop]: https://web.archive.org/web/20200422110605/https://drupalcamp.london/training/Automated-Testing-and-Test-Driven-Development-in-Drupal-8

View file

@ -0,0 +1,100 @@
---
title: Testimonials
use: [posts]
testimonials:
- name: Ed Welsby
image: ed-welsby.png
role: Senior Developer at <a class="text-blue-600 inline-block" href="http://www.proctors.co.uk">Proctor & Stevenson</a>
text: |
Oliver was great to work with, he has a solid knowledge of the various aspects of web development and never minded helping me out with Linux commands!
- name: Brian Healy
image: brian-healy.png
role: Director of Business Development at <a class="text-blue-600 inline-block" href="http://tincan.co.uk">Tincan</a>.
text: |
Oliver was fantastic to work with - pro-active and highly responsive, he worked well remotely and as part of a project team. His understanding of the project requirement(s) and ability to translate it into working code was essential and he delivered.
- name: Marlon Duncanson
role: 'Brand & Web Specialist'
text: |
Oliver is a great guy and really easy to work with. He really goes the extra mile to make sure the project is done properly. I would recommend him and will not hesitate to use him again in future.
- name: Brian Hartwell
role: Interactive Creative Director
text: |
Oliver was great to work with. He has expert knowledge with Drupal and delivered exactly what we were looking for on time. He's understanding, friendly and easy to get along with. I would enjoy working with him again in the future.
- name: Daniel Easterbrook
role: Digital Strategy Consultant
text: |
Oliver is seasoned Drupal and all round highly skilled and experienced web developer. I have worked with Oliver on an important project where he was reliable, prompt and ensured strict client deadline delivery and confidentiality at all times.
- name: James Chapman
role: Director at <a class="text-blue-600 inline-block" href="http://www.developmentdoneright.co.uk">Development Done Right</a>
image: james-chapman.png
text: |
We used Oliver on a number of occasions throughout 2012 and I have to say we've been delighted with his work. His skills working with Drupal are excellent particularly with custom module development and we wouldnt hesitate to recommend him others.
- name: Léonie Watson
role: >
Director of Accessibility at <a class="text-blue-600 inline-block" href="http://www.nomensa.com">Nomensa</a>
image: leonie-watson.jpg
text: |
Oliver is a flexible and hardworking developer, with a terrific knowledge of Drupal. He promotes accessibility best practice within the Drupal community, and is always happy to share his knowledge with other people.
- name: Holly Ross
role: >
Executive Director at the <a class="text-blue-600 inline-block" href="https://assoc.drupal.org">Drupal Association</a>
image: holly-ross.png
text: |
Oliver has been an outstanding contributor to the Drupal Association team. He is a talented developer who writes great code and applies his curiosity and love of learning to every project. He is also a fantastic team member, who gives to the team as much as he gets.
Oliver is the embodiment of everything good about the Drupal community.
- name: Josh Mitchell
role: CTO at the <a class="text-blue-600 inline-block" href="https://assoc.drupal.org">Drupal Association</a>
image: josh-mitchell.png
text: |
Oliver is a skilled Drupal developer with a passion for the Drupal community. As his direct supervisor, I was able to watch Oliver grow with the Drupal Association and contribute an amazing amount of effort and integrity to all of his work.
Everything we have thrown at Oliver, he has approached with an open and flexible mind that has allowed him to work on a wide range of projects and features for Drupal products.
- name: Chris Jarvis
image: chris-jarvis.jpg
role: Developer at <a class="text-blue-600 inline-block" href="https://microserve.io">Microserve</a>
text: |
Oliver is an amazing colleague, he's professional, full of knowledge and I could not recommend him more.
---
{% block content %}
<div class="spaced-y-12">
{% for testimonial in page.testimonials|reverse %}
<article class="flex flex-row-reverse items-center">
{% if testimonial.image %}
<div class="flex-none">
<img
src="{{ site.url }}/images/testimonials/{{ testimonial.image }}"
alt="{{ testimonial.name }}"
class="with-border with-padding rounded-full w-16 h-16 ml-4"
>
</div>
{% endif %}
<div class="flex-1">
<div class="mb-3">
<h2 class="mb-1 leading-none">{{ testimonial.name }}</h2>
{% if testimonial.role %}
<div class="text-gray-600 text-sm">
{{ testimonial.role|raw }}
</div>
{% endif %}
</div>
<div class="markup">
{{ testimonial.text|markdown }}
</div>
</div>
</article>
{% endfor %}
</div>
{% endblock %}

View file

@ -0,0 +1,11 @@
<div class="widget">
<h2 class="mb-2">Availability</h2>
<ul class="list-disc pl-5">
{% for type, value in site.availability %}
<li>
{% include 'about/availability/' ~ value %}
</li>
{% endfor %}
</ul>
</div>

View file

@ -0,0 +1 @@
Currently have limited {{ type }}-time capacity.

View file

@ -0,0 +1 @@
Currently no spare {{ type }}-time capacity.

View file

@ -0,0 +1 @@
Currently have available {{ type }}-time capacity.

View file

@ -0,0 +1,60 @@
<aside class="block sm:flex md:block -mx-4">
<div class="px-4">
<section class="widget">
<div class="max-w-xs md:max-w-full mx-auto">
<a href="https://assoc.drupal.org/membership" title="Im a Drupal Association member." class="block mb-4 px-4 md:px-0 mx-10">
<img src="/images/badges/da-individual-member.png" alt="Drupal Association Individual Member"/>
</a>
</div>
</section>
</div>
<div class="px-4">
<section class="widget bg-gray-300 p-4 rounded">
<div class="-mb-3">
<h2 class="visuallyhidden">Certifications</h2>
{% include 'about/certification' with {
title: 'Acquia certified Grand Master - Drupal 8',
url: 'http://certification.acquia.com/user/1647756',
image: {
filename: 'acquia-d8-grand-master.png',
alt: 'Acquia Certified Grand Master - Drupal 8 Exam Badge',
},
} %}
{% include 'about/certification' with {
title: 'Acquia certified Developer - Drupal 8',
image: {
filename: 'acquia-d8-developer.png',
alt: 'Acquia Certified Developer - Drupal 8 Exam Badge',
},
} %}
{% include 'about/certification' with {
title: 'Acquia certified Back End Specialist - Drupal 8',
image: {
filename: 'acquia-d8-back-end.png',
alt: 'Acquia Certified Back End Specialist - Drupal 8 Exam Badge',
},
} %}
{% include 'about/certification' with {
title: 'Acquia certified Front End Specialist - Drupal 8',
image: {
filename: 'acquia-d8-front-end.png',
alt: 'Acquia Certified Front End Specialist - Drupal 8 Exam Badge',
},
} %}
{% include 'about/certification' with {
title: 'Acquia certified Cloud Pro',
image: {
filename: 'acquia-cloud-pro.png',
alt: 'Acquia Certified Cloud Pro Exam Badge',
},
} %}
</div>
</section>
</div>
</aside>

View file

@ -0,0 +1,17 @@
<div class="flex mb-3">
<div class="w-16 mr-2 flex-none">
<div class="flex flex-col items-center">
<img src="/images/badges/{{ image.filename }}" alt="{{ image.alt }}" />
</div>
</div>
<div class="flex items-center ml-px">
<p class="text-sm mb-0 mr-1">
{% if url %}
<a href="{{ url }}" class="no-underline hover:underline focus:underline">{{ title }}</a>
{% else %}
{{ title }}
{% endif %}
</p>
</div>
</div>

View file

@ -0,0 +1,31 @@
<div>
<div>
<h2 class="text-inherit text-lg m-0 leading-snug">
<a
href="{{ post.external_url ?: post.url }}"
class="text-inherit"
tabindex="-1"
>
{{ post.draft ? 'Draft: '|upper }}{{ post.title }}
</a>
</h2>
{% if show_date %}
{% include 'posts/post-date' with { class: 'mt-1 text-sm block' } %}
{% endif %}
</div>
<div class="mt-2">
<p>{{ post.excerpt }}</p>
</div>
{% if not post.type == 'tweet' %}
<div class="mt-1">
<a href="{{ post.url }}" class="text-sm text-gray-600 hover:text-gray-800">
Read more
<span class="visuallyhidden">about '{{ post.title }}'</span>
&rarr;
</a>
</div>
{% endif %}
</div>

View file

@ -0,0 +1,7 @@
<h2>Certifications</h2>
<ul>
{% for certification in page.certifications %}
<li>{{ certification.title }}</li>
{% endfor %}
</ul>

View file

@ -0,0 +1,21 @@
<h2>Experience</h2>
<ul class="list-reset">
{% for item in page.experience %}
<li class="mb-12">
{% if site.companies[item.company].url %}
<h3><a href="{{ site.companies[item.company].url }}" class="text-inherit no-underline hover:underline focus:bg-gray-900">{{ site.companies[item.company].name }}</a></h3>
{% else %}
<h3>{{ site.companies[item.company].name }}</h3>
{% endif %}
{% for role in item.roles %}
<div>
<h4 class="mb-3 text-gray-800">{{ role.title }} from {{ role.from }} to {{ role.to ?: 'present' }} ({{ role.location }})</h4>
{{ role.description|markdown }}
</div>
{% endfor %}
</li>
{% endfor %}
</ul>

View file

@ -0,0 +1,8 @@
<figure class="block">
<img src="{{ image.src }}" alt="{{ image.alt }}" class="p-1 border">
{% if caption %}
<figcaption class="mt-1 mb-0 italic text-sm text-center text-gray-800">
{{ caption }}
</figcaption>
{% endif %}
</figure>

View file

@ -0,0 +1,17 @@
<footer class="border-gray-300 border-t mb-8 mt-10 pt-5 text-sm">
<div class="md:flex md:justify-between">
<div>
<p>&copy; 2010-{{ 'now'|date('Y') }} {{ site.title }}</p>
</div>
<div class="mt-4 md:mt-0">
<p>
Built with <a href="https://sculpin.io">Sculpin</a>,
<a href="https://vuejs.org">Vue.js</a>
and <a href="https://tailwindcss.com">Tailwind CSS</a>,
stored on <a href="https://github.com/opdavies/oliverdavies.uk">GitHub</a>
and hosted on <a href="https://www.netlify.com">Netlify</a>.
</p>
</div>
</div>
</footer>

View file

@ -0,0 +1,47 @@
<div id="nav" class="bg-blue-500 border-b-3 border-blue-700">
<div class="container">
<div class="md:flex" x-data="{ isOpen: false }">
<div class="w-full flex items-center md:w-1/3 lg:w-1/4">
<div class="w-3/4 py-6">
<div class="text-sm">
<a href="{{ site.menus.main.about.href }}" class="font-semibold text-white" tabindex="-1">
{{ site.title }}
</a>
</div>
</div>
<div class="w-1/4 text-right flex items-center justify-end md:hidden">
<button
type="button"
class="nav-toggle appearance-none text-white hover:text-gray-300 focus:outline-none"
aria-label="Toggle main menu"
@click="isOpen = !isOpen"
>
<svg class="js-hidden fill-current text-inherit w-6 h-6" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 20 20">
<path x-show="!isOpen" d="M16.4 9H3.6c-.552 0-.6.447-.6 1 0 .553.048 1 .6 1h12.8c.552 0 .6-.447.6-1 0-.553-.048-1-.6-1zm0 4H3.6c-.552 0-.6.447-.6 1 0 .553.048 1 .6 1h12.8c.552 0 .6-.447.6-1 0-.553-.048-1-.6-1zM3.6 7h12.8c.552 0 .6-.447.6-1 0-.553-.048-1-.6-1H3.6c-.552 0-.6.447-.6 1 0 .553.048 1 .6 1z"/>
<path x-show="isOpen" d="M10 8.586L2.929 1.515 1.515 2.929 8.585 10l-7.07 7.071 1.414 1.414L10 11.415l7.071 7.07 1.414-1.414L11.415 10l7.07-7.071-1.414-1.414L10 8.585z" fill-rule="evenodd"/>
</svg>
</button>
</div>
</div>
<nav
class="mt-2px -mx-4 py-4 bg-blue-700 md:mt-0 md:mx-0 md:relative md:flex md:flex-wrap md:flex-1 md:justify-end md:bg-blue-500 md:border-b-0"
:class="[ isOpen ? 'block' : 'hidden' ]"
>
{% for item in site.menus.main %}
{% set currentPage = page.url matches '#' ~ item.pattern ~ '#' %}
<a
class="mx-4 mt-1 -mb-px py-3 px-4 block rounded text-sm text-white no-underline hover:underline focus:outline-none focus:underline md:py-1 md:px-2 md:mx-2 md:mt-0 md:mr-0 {{ currentPage ? 'cursor-default bg-blue-500 hover:border-blue-600 hover:no-underline md:bg-blue-700' }}"
href="{{ item.href }}"
{% if currentPage %}aria-current="page"{% endif %}
>
<span class="flex items-center h-full">
{{- item.title -}}
</span>
</a>
{% endfor %}
</nav>
</div>
</div>
</div>

View file

@ -0,0 +1,20 @@
{% macro canonicalUrl(site, page) -%}
{{ site.url }}
{{- page.url != '//' ? page.url }}
{%- endmacro %}
{% import _self as helpers %}
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1">
<link rel="alternate" type="application/rss+xml" title="{{ site.title }} RSS" href="{{ site.url }}/feed">
<link rel="canonical" href="{{ helpers.canonicalUrl(site, page) }}">
{% if page.meta.description %}
<meta name="description" content="{{ page.meta.description|e('html') }}">
{% else %}
<meta name="description" content="Oliver Davies is a UK-based Web Developer and System Administrator. He is a {{ site.work.role }} at {{ site.companies[site.work.company].name }} and a part-time freelancer, specialising in Drupal and PHP.">
{% endif %}
{% include 'og' with { og: page.meta.og } %}

View file

@ -0,0 +1,40 @@
<meta property="og:url" content="{{ site.url }}{{ page.url }}">
<meta property="og:title" content="{{ og.title ? og.title|raw : page.title|raw }}"/>
{% if og.description %}
<meta property="og:description" content="{{ og.description|raw }}"/>
{% endif %}
{% if og.type %}
<meta property="og:type" content="{{ og.type }}"/>
{% endif %}
{% if page.image.url %}
<meta property="og:image" content="{{ site.url }}{{ page.image.url }}"/>
{% if page.image.type %}
<meta property="og:image:type" content="{{ page.image.type }}"/>
{% endif %}
{% if page.image.width %}
<meta property="og:image:width" content="{{ page.image.width }}"/>
{% endif %}
{% if page.image.height %}
<meta property="og:image:height" content="{{ page.image.height }}"/>
{% endif %}
{% else %}
<meta property="og:image" content="{{ site.url }}{{ site.avatar.url }}"/>
<meta property="og:image:height" content="327"/>
<meta property="og:image:type" content="image/jpg">
<meta property="og:image:width" content="327"/>
{% endif %}
{% if page.image %}
<meta name="twitter:card" content="summary_large_image"/>
<meta name="twitter:image" content="{{ site.url }}{{ page.image.url }}">
{% else %}
<meta name="twitter:card" content="summary"/>
<meta name="twitter:image" content="{{ site.url }}{{ site.avatar.url }}">
{% endif %}
{% if page.hide_page %}
<meta name="robots" content="no-index, no-follow">
{% endif %}

View file

@ -0,0 +1,27 @@
<div class="md:flex md:flex-wrap md:-mx-2">
{% for project in projects %}
<div class="md:w-1/2 md:px-2 mb-4 flex">
<div class="border p-3 w-full flex flex-col {{ project.versions ? 'justify-between' }}">
<h3>
<a href="{{ project.url }}" class="text-black no-underline hover:underline focus:underline">
{{ project.name }}
</a>
</h3>
<div class="markup flex-1">
{{ project.description }}
</div>
{% if project.versions %}
<div class="mt-4 text-right">
{% for version in project.versions %}
<span class="text-xs ml-1 px-1 py-1 bg-gray-300 text-gray-600 rounded">{% spaceless %}
Drupal {{ version }}
{% endspaceless %}</span>
{% endfor %}
</div>
{% endif %}
</div>
</div>
{% endfor %}
</div>

View file

@ -0,0 +1,14 @@
<div class="w-full lg:w-2/3">
<form action="{{ page.mailchimp_url }}" method="post" name="mc-embedded-subscribe-form" novalidate="">
<div id="mc_embed_signup_scroll">
<div style="position: absolute; left: -5000px;" aria-hidden="true">
<input type="text" name="b_46d1ff41a9918b3b7efb885dc_6df88a3d0f" tabindex="-1" value="">
</div>
<div class="flex overflow-hidden">
<input type="email" value="" name="EMAIL" class="required email block w-full border border-gray p-3 pl-5 rounded-l-full" placeholder="enter your email" aria-label="Email">
<button type="submit" name="subscribe" class="block w-auto border border-gray border-l-0 py-3 pl-5 pr-6 rounded-r-full bg-blue-600 text-white">Subscribe</button>
</div>
</div>
</form>
</div>

View file

@ -0,0 +1,41 @@
<div class="py-8 text-center">
<ul class="list-reset inline-flex">
<li>
{% if page.pagination.page == 1 %}
<span class="rounded-l-lg p-3 border border-gray text-gray -mr-px cursor-not-allowed">
Previous
</span>
{% else %}
<a href="{{ page.pagination.previous_page.url }}" class="rounded-l-lg link no-underline hover:underline hover:bg-gray-200 focus:underline p-3 border border-gray -mr-px">
Previous
</a>
{% endif %}
</li>
{% for i in range(1, page.pagination.total_pages) %}
<li class="{{ i > (page.pagination.page + 2) or i < (page.pagination.page - 2) ? 'hidden sm:block' }}">
{% if i == page.pagination.page %}
<span class="p-3 border border-gray text-white bg-blue-600 -mr-px">
{{ i }}
</span>
{% else %}
<a href="{{ i == 1 ? '/blog' : '/blog/page/' ~ i ~ '.html' }}" class="link no-underline hover:underline hover:bg-gray-200 focus:underline p-3 border border-gray -mr-px">
{{ i }}
</a>
{% endif %}
</li>
{% endfor %}
<li>
{% if page.pagination.next_page.url %}
<a href="{{ page.pagination.next_page.url }}" class="rounded-r-lg link no-underline hover:underline hover:bg-gray-200 focus:underline p-3 border border-gray">
Next
</a>
{% else %}
<span class="rounded-r-lg p-3 border border-gray text-gray cursor-not-allowed">
Next
</span>
{% endif %}
</li>
</ul>
</div>

View file

@ -0,0 +1,14 @@
<div>
<h2 class="mb-2">About the Author</h2>
<div class="flex items-center">
<div class="mr-4 flex-none leading-none">
<img src="{{ site.avatar.url }}" alt="Picture of Oliver" class="w-16 rounded-full border border-gray">
</div>
<p class="markup mb-0">
Oliver Davies is a Full Stack Web Developer and System Administrator based in the UK.
He is a {{ site.work.role }} at <a href="{{ site.companies[site.work.company].url }}?utm_source={{ site.short_url }}&amp;utm_medium=about-author" class="link">{{ site.companies[site.work.company].name }}</a> and a part-time freelancer specialising in Drupal, Symfony and Laravel development and Linux systems administration.
</p>
</div>
</div>

View file

@ -0,0 +1,3 @@
<p class="mb-4 italic text-gray-600">
<b>Have feedback on this post?</b> <a href="mailto:{{ site.email }}?subject=Feedback: {{ page.title }}">Email me</a> or <a href="https://twitter.com/intent/tweet?text=@{{ site.twitter.user }}&url={{ site.url }}{{ page.url|url_encode }}">send me a tweet</a>.
</p>

View file

@ -0,0 +1,7 @@
<div class="mb-8">
<h1 class="leading-tight mb-2">{{ page.title }}</h1>
<p class="text-gray-600">
{% include 'posts/post-date' with { post: page } %}
</p>
</div>

View file

@ -0,0 +1,5 @@
{% if page.blocks.intro_image %}
<div class="mv3 tc">
{{ page.blocks.intro_image|raw }}
</div>
{% endif %}

View file

@ -0,0 +1,8 @@
{% if page.date|date('U') < 'now'|date_modify('-12 months')|date('U') %}
<div class="border-2 border-blue-600 p-4 mb-6">
<p class="text-sm mb-0">
<span class="font-bold">Warning:</span>
This post is over a year old. I don't always update old posts with new information, so some of this information may be out of date.
</p>
</div>
{% endif %}

View file

@ -0,0 +1,6 @@
<section class="border-b border-t mb-4 mt-8 py-4">
<p>
Questions? Comments?
Im <a href="https://twitter.com/{{ site.twitter.user }}">@{{ site.twitter.user }}</a> on Twitter.
</p>
</section>

View file

@ -0,0 +1,11 @@
{% if page.related -%}
<h2>Related Posts</h2>
<ul>
{% for relate in page.related -%}
<li>
<a href="{{ relate.source.url }}">{{ relate.title }}</a>
</li>
{% endfor %}
</ul>
{%- endif %}

View file

@ -0,0 +1,13 @@
{% if page.tags %}
<h2 class="visuallyhidden">Tags</h2>
<ul class="list-reset flex flex-wrap spaced-y-2 spaced-x-3">
{% for tag in page.tags|sort %}
<li>
<a href="/blog/tags/{{ tag }}" class="text-xs py-1 px-3 border-l-2 border-gray-500 bg-gray-200 text-gray-800 leading-none no-underline hover:underline focus:bg-gray-800 focus:text-white focus:outline-none">
{{- tag -}}
</a>
</li>
{% endfor %}
</ul>
{% endif %}

View file

@ -0,0 +1,15 @@
{% if data.posts and page.url != '/blog' %}
<div class="markup">
<h2 class="mb-2">Latest Blog Posts</h2>
<ul class="pl-4">
{% for post in data.posts|slice(0, site.latest_posts) %}
<li>
<a href="{{ post.url }}">
{{- post.title -}}
</a>
</li>
{% endfor %}
</ul>
</div>
{% endif %}

View file

@ -0,0 +1,4 @@
<time class="{{ class }}" datetime="{{ post.date|date('Y-m-d') }}">
<span class="visuallyhidden">Posted on </span>
{{ post.date|date('jS F Y') }}
</time>

View file

@ -0,0 +1,4 @@
<div class="markup mb-8 px-5 py-3 text-sm border-b-2 border-yellow-300 bg-yellow-100">
<p>Oliver is giving a workshop, <a href="https://opdavi.es/dclondon20">Automated Testing and Test Driven Development with Drupal 8</a>, on 13th March at DrupalCamp London.</p>
<p><a href="http://opdavi.es/YilTZ" title="Find out more and register on the DrupalCamp London website">Find out more and register</a> on the DrupalCamp London website.</p>
</div>

View file

@ -0,0 +1,9 @@
<div class="slides">
<noscript>**Please enable JavaScript to view slides.**</noscript>
<script
class="speakerdeck-embed"
data-id="{{ data.id }}"
data-ratio="{{ data.ratio ?: '1.29456384323641' }}"
src="//speakerdeck.com/assets/embed.js"
></script>
</div>

View file

@ -0,0 +1,7 @@
<svg viewBox="0 0 20 20" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" class="{{ class }}" style="{{ style }}">
<g stroke="none" stroke-width="1" fill-rule="evenodd">
<g id="icon-shape">
<polygon id="Combined-Shape" points="12.9497475 10.7071068 13.6568542 10 8 4.34314575 6.58578644 5.75735931 10.8284271 10 6.58578644 14.2426407 8 15.6568542 12.9497475 10.7071068"></polygon>
</g>
</g>
</svg>

After

Width:  |  Height:  |  Size: 476 B

View file

@ -0,0 +1,17 @@
{% import 'helpers' as helpers %}
{% if events %}
<div>
<h2>Presented at</h2>
<ul class="markup mt-2 list-disc ml-5">
{% for event in events %}
<li>
{{ helpers.talkEventName(event) }}
{{ helpers.talkEventLocation(event) }}
<span class="text-gray-800">- {{ event.date|date('jS F Y') }}</span>
</li>
{% endfor %}
</ul>
</div>
{% endif %}

Some files were not shown because too many files have changed in this diff Show more