refactor: move website files to the root level
This commit is contained in:
parent
c2887ecbc5
commit
2cbbfd60ff
590 changed files with 0 additions and 4484 deletions
7
src/pages/404.mdx
Normal file
7
src/pages/404.mdx
Normal file
|
|
@ -0,0 +1,7 @@
|
|||
---
|
||||
title: Page not found
|
||||
---
|
||||
|
||||
import Layout from '~/layouts/PageLayout.astro'
|
||||
|
||||
<Layout title={frontmatter.title} />
|
||||
19
src/pages/ansible-course.mdx
Normal file
19
src/pages/ansible-course.mdx
Normal file
|
|
@ -0,0 +1,19 @@
|
|||
---
|
||||
layout: ~/layouts/PageLayout.astro
|
||||
title: Ansible email course
|
||||
---
|
||||
|
||||
<script src="https://f.convertkit.com/ckjs/ck.5.js"></script>
|
||||
|
||||
Register for my upcoming Ansible email course.
|
||||
|
||||
<form class="mx-auto mt-8 max-w-md" action="https://app.convertkit.com/forms/3588392/subscriptions" method="post" data-sv-form="3588392" data-uid="f0c1d2b57f" data-format="inline" data-version="5" data-options="{"settings":{"after_subscribe":{"action":"message","success_message":"Success! Now check your email to confirm your subscription.","redirect_url":""},"analytics":{"google":null,"fathom":null,"facebook":null,"segment":null,"pinterest":null,"sparkloop":null,"googletagmanager":null},"modal":{"trigger":"timer","scroll_percentage":null,"timer":5,"devices":"all","show_once_every":15},"powered_by":{"show":true,"url":"https://convertkit.com/features/forms?utm_campaign=poweredby&utm_content=form&utm_medium=referral&utm_source=dynamic"},"recaptcha":{"enabled":false},"return_visitor":{"action":"show","custom_content":""},"slide_in":{"display_in":"bottom_right","trigger":"timer","scroll_percentage":null,"timer":5,"devices":"all","show_once_every":15},"sticky_bar":{"display_in":"top","trigger":"timer","scroll_percentage":null,"timer":5,"devices":"all","show_once_every":15}},"version":"5"}" min-width="400"><div data-style="clean"><ul class="formkit-alert formkit-alert-error" data-element="errors" data-group="alert"></ul>
|
||||
<div data-element="fields" data-stacked="false" class="seva-fields formkit-fields"><div class="formkit-field">
|
||||
<input class="block mt-1 w-full" name="email_address" style="color: rgb(0, 0, 0); border-color: rgb(227, 227, 227); border-radius: 4px; font-weight: 400;" aria-label="Email Address" placeholder="What is your best email address?" required="" type="email"/>
|
||||
</div>
|
||||
<div class="mt-4">
|
||||
<button data-element="submit" class="inline-flex justify-center items-center py-3 px-6 w-full font-medium text-white no-underline rounded-md border duration-200 ease-in-out hover:bg-white focus:bg-white border-blue-primary bg-blue-primary transition-color hover:text-blue-primary focus:text-blue-primary">
|
||||
<div class="formkit-spinner"><div></div><div></div><div></div></div><span class="">Register for updates →</span>
|
||||
</button></div>
|
||||
</div>
|
||||
</div></form>
|
||||
20
src/pages/archive.xml.js
Normal file
20
src/pages/archive.xml.js
Normal file
|
|
@ -0,0 +1,20 @@
|
|||
import rss from '@astrojs/rss';
|
||||
|
||||
const emailImportResult = import.meta.glob('../daily-emails/*.md', { eager: true });
|
||||
const emails = Object.values(emailImportResult)
|
||||
.sort((a, b) =>
|
||||
new Date(b.frontmatter.pubDate).valueOf() -
|
||||
new Date(a.frontmatter.pubDate).valueOf()
|
||||
)
|
||||
|
||||
export const get = () => rss({
|
||||
title: 'Daily email list',
|
||||
description: 'A daily newsletter on software development, DevOps, community, and open-source.',
|
||||
site: import.meta.env.SITE,
|
||||
items: emails.slice(0, 1).map((email) => ({
|
||||
description: `<div style="max-width: 550px;">${email.compiledContent()}</div>`,
|
||||
link: `${import.meta.env.SITE}${email.frontmatter.permalink}`,
|
||||
title: email.frontmatter.title,
|
||||
pubDate: email.frontmatter.pubDate,
|
||||
}))
|
||||
});
|
||||
41
src/pages/archive/[...page].astro
Normal file
41
src/pages/archive/[...page].astro
Normal file
|
|
@ -0,0 +1,41 @@
|
|||
---
|
||||
import DailyEmailForm from "~/components/DailyEmailForm.astro";
|
||||
import Layout from "~/layouts/DailyEmailLayout.astro";
|
||||
|
||||
export async function getStaticPaths({ paginate }) {
|
||||
const emails = await Astro.glob("../../daily-emails/*.{md,mdx}");
|
||||
const sortedEmails = emails.sort(
|
||||
(a, b) =>
|
||||
new Date(b.frontmatter.pubDate).valueOf() -
|
||||
new Date(a.frontmatter.pubDate).valueOf()
|
||||
);
|
||||
|
||||
return paginate(sortedEmails, { pageSize: 20 });
|
||||
}
|
||||
|
||||
const { page } = Astro.props;
|
||||
---
|
||||
|
||||
<Layout title={"Daily email archive"}>
|
||||
<ul>
|
||||
{
|
||||
page.data.map((email) => (
|
||||
<li>
|
||||
<a href={`/${email.frontmatter.permalink}`}>
|
||||
{new Date(email.frontmatter.pubDate).toLocaleDateString("en-GB", {
|
||||
day: "numeric",
|
||||
month: "long",
|
||||
year: "numeric",
|
||||
})}:
|
||||
{email.frontmatter.title}
|
||||
</a>
|
||||
</li>
|
||||
))
|
||||
}
|
||||
</ul>
|
||||
|
||||
<nav class="flex justify-center pt-10 space-x-6">
|
||||
{page.url.prev ? <a href={page.url.prev}>← Newer emails</a> : null}
|
||||
{page.url.next ? <a href={page.url.next}>Older emails →</a> : null}
|
||||
</nav>
|
||||
</Layout>
|
||||
36
src/pages/archive/[year]/[month]/[day]/[slug].astro
Normal file
36
src/pages/archive/[year]/[month]/[day]/[slug].astro
Normal file
|
|
@ -0,0 +1,36 @@
|
|||
---
|
||||
import DailyEmailForm from "~/components/DailyEmailForm.astro";
|
||||
import Layout from "~/layouts/DailyEmailLayout.astro";
|
||||
|
||||
export async function getStaticPaths() {
|
||||
const emails = await Astro.glob("../../../../../daily-emails/*.{md,mdx}");
|
||||
|
||||
return emails.map((email) => {
|
||||
const pubDate = email.frontmatter.pubDate.split("T")[0].split("-");
|
||||
|
||||
const slug = email.frontmatter.permalink
|
||||
.replace("archive/", "")
|
||||
.replace("\n", "");
|
||||
const slugParts = slug.split("/");
|
||||
|
||||
return {
|
||||
params: {
|
||||
day: pubDate[2],
|
||||
month: pubDate[1],
|
||||
slug: slugParts.reverse()[0],
|
||||
year: pubDate[0],
|
||||
},
|
||||
props: {
|
||||
email,
|
||||
},
|
||||
};
|
||||
});
|
||||
}
|
||||
|
||||
const { Content } = Astro.props.email;
|
||||
const { title } = Astro.props.email.frontmatter;
|
||||
---
|
||||
|
||||
<Layout title={title}>
|
||||
<Content />
|
||||
</Layout>
|
||||
32
src/pages/blog/[slug].astro
Normal file
32
src/pages/blog/[slug].astro
Normal file
|
|
@ -0,0 +1,32 @@
|
|||
---
|
||||
import AboutMe from "~/components/AboutMe.astro";
|
||||
import Layout from "~/layouts/Layout.astro";
|
||||
import Markdown from "~/components/Markdown.astro";
|
||||
import { getSlugFromFile } from "~/utils.ts";
|
||||
|
||||
export async function getStaticPaths() {
|
||||
const posts = await Astro.glob("../../posts/*.md");
|
||||
|
||||
return posts.map((post) => {
|
||||
const slug = getSlugFromFile(post.file);
|
||||
|
||||
return {
|
||||
params: { slug },
|
||||
props: { post },
|
||||
};
|
||||
});
|
||||
}
|
||||
|
||||
const { Content } = Astro.props.post;
|
||||
const { title } = Astro.props.post.frontmatter;
|
||||
---
|
||||
|
||||
<Layout title={title}>
|
||||
<div class="space-y-6">
|
||||
<Markdown>
|
||||
<Content />
|
||||
</Markdown>
|
||||
|
||||
<AboutMe />
|
||||
</div>
|
||||
</Layout>
|
||||
32
src/pages/blog/index.astro
Normal file
32
src/pages/blog/index.astro
Normal file
|
|
@ -0,0 +1,32 @@
|
|||
---
|
||||
import ListingPage from "~/components/ListingPage.astro";
|
||||
import PageLayout from "~/layouts/PageLayout.astro";
|
||||
import { getSlugFromFile } from "~/utils.ts";
|
||||
|
||||
const posts = await Astro.glob("../../posts/*.md");
|
||||
|
||||
// TODO: show all posts when running locally.
|
||||
const filteredPosts = posts
|
||||
.filter((post) => !post.frontmatter.draft)
|
||||
.filter((post) => post.frontmatter.date);
|
||||
|
||||
const sortedPosts = filteredPosts
|
||||
.map((post) => {
|
||||
const slug = `/blog/${getSlugFromFile(post.file)}`;
|
||||
|
||||
return { item: post, slug };
|
||||
})
|
||||
.sort(
|
||||
(a, b) =>
|
||||
new Date(b.item.frontmatter.date).valueOf() -
|
||||
new Date(a.item.frontmatter.date).valueOf()
|
||||
);
|
||||
---
|
||||
|
||||
<ListingPage items={sortedPosts} title="Blog">
|
||||
<p slot="intro">
|
||||
This is where I publish my personal blog posts as well as technical posts
|
||||
and tutorials on topics such as Drupal, PHP, Tailwind CSS, automated
|
||||
testing, and systems administration.
|
||||
</p>
|
||||
</ListingPage>
|
||||
31
src/pages/call.mdx
Normal file
31
src/pages/call.mdx
Normal file
|
|
@ -0,0 +1,31 @@
|
|||
---
|
||||
layout: ~/layouts/PageLayout.astro
|
||||
title: Book a 1-on-1 consulting call
|
||||
link: https://savvycal.com/opdavies/consulting-call
|
||||
price: 199
|
||||
---
|
||||
|
||||
## How it works
|
||||
|
||||
- You book a 60 minute consulting call with me.
|
||||
- Once payment is received, you’ll obtain a link to schedule a meeting in my calendar.
|
||||
- The meeting will take place over Zoom.
|
||||
|
||||
<a class="my-4 py-2 px-5 inline-block rounded-lg border-2 border-blue-primary text-lg bg-blue-primary text-white no-underline transition-colors duration-200 hover:bg-white hover:text-blue-primary" href={frontmatter.link}>Book your call now →</a>
|
||||
|
||||
If you don’t find the call valuable, I’ll refund 100% of the cost.
|
||||
|
||||
### Typical subjects of interest include
|
||||
|
||||
- How to approach a new project or task.
|
||||
- Help writing your first automated test or starting with test-driven development.
|
||||
- Introducing static analysis or other code quality tools to your project.
|
||||
- Automating tasks with Docker and/or Ansible.
|
||||
- Help to fix a bug or some broken code.
|
||||
- Reviewing your code and providing advice and suggestions.
|
||||
|
||||
<aside class="p-6 my-8 border border-gray-300 dark:bg-gray-800 dark:border-gray-700" markdown="1">
|
||||
<h2 class="mt-0">Ready to book your call?</h2>
|
||||
|
||||
<a class="mt-4 py-2 px-5 inline-block rounded-lg border-2 border-blue-primary text-lg bg-blue-primary text-white no-underline transition-colors duration-200 hover:bg-white hover:text-blue-primary" href={frontmatter.link}>Book now for £{frontmatter.price} →</a>
|
||||
</aside>
|
||||
10
src/pages/company-information.mdx
Normal file
10
src/pages/company-information.mdx
Normal file
|
|
@ -0,0 +1,10 @@
|
|||
---
|
||||
layout: ~/layouts/PageLayout.astro
|
||||
title: 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
|
||||
12
src/pages/contact.mdx
Normal file
12
src/pages/contact.mdx
Normal file
|
|
@ -0,0 +1,12 @@
|
|||
---
|
||||
layout: ~/layouts/PageLayout.astro
|
||||
title: Contact Oliver
|
||||
---
|
||||
|
||||
export const email = 'oliver@oliverdavies.uk'
|
||||
|
||||
The best way to get in touch with me is via email: <a href={`mailto:${email}`}>{email}</a>. I usually reply within one business day.
|
||||
|
||||
I'm also on [LinkedIn][linkedin].
|
||||
|
||||
[linkedin]: https://www.linkedin.com/in/opdavies
|
||||
68
src/pages/daily.mdx
Normal file
68
src/pages/daily.mdx
Normal file
|
|
@ -0,0 +1,68 @@
|
|||
---
|
||||
layout: ~/layouts/PageLayout.astro
|
||||
title: Oliver's Daily List
|
||||
---
|
||||
|
||||
import AboutMe from '~/components/AboutMe.astro';
|
||||
import DailyEmailForm from '~/components/DailyEmailForm.astro';
|
||||
import Markdown from '~/components/Markdown.astro';
|
||||
import _ from 'lodash'
|
||||
|
||||
export const testimonials = [
|
||||
{
|
||||
name: "Patty O'Callaghan",
|
||||
text: "<p>Just wanted to say that your blog is amazing <3 I absolutely love it and usually share it with colleagues and some of the kids at my Code Club.</p><p>Thanks for contributing to the community with your amazing content! :)</p>",
|
||||
image: "patty-ocallaghan.jpg"
|
||||
},
|
||||
{
|
||||
name: "Stephen Mulvihill",
|
||||
text: "I like the \"$ git log -S\" and \"$ git log --grep\" commands, will definitely be using these, thanks!",
|
||||
image: "stephen-mulvihill.jpg"
|
||||
},
|
||||
{
|
||||
name: "Marcos Duran",
|
||||
text: "<p> I am a big fan of your git approaches. I especially remember pairing with you and watching how many commands you run to solve many problems and how fast you were. It's a skill I believe not many have, particularly those who are used to working with a GUI like me, and personally I think it is quite valuable.</p>",
|
||||
image: "marcos-duran.jpg"
|
||||
}
|
||||
]
|
||||
|
||||
export const sortedTestimonials = _.reverse(testimonials)
|
||||
|
||||
A daily newsletter on software development, DevOps, community, and open-source.
|
||||
|
||||
<div class="space-y-12">
|
||||
<div class="space-y-20">
|
||||
<DailyEmailForm />
|
||||
|
||||
{sortedTestimonials && (
|
||||
<section>
|
||||
<h2 class="sr-only">Testimonials</h2>
|
||||
|
||||
<div class="space-y-12">
|
||||
{testimonials.map(testimonial => (
|
||||
<article class="flex space-x-10">
|
||||
<div>
|
||||
<blockquote class="m-0">
|
||||
<Markdown set:html={testimonial.text} />
|
||||
</blockquote>
|
||||
|
||||
<figcaption class="mt-6">{testimonial.name}</figcaption>
|
||||
</div>
|
||||
|
||||
<div class="flex-shrink-0 hidden sm:block">
|
||||
<img
|
||||
alt={testimonial.name}
|
||||
class="border border-grey rounded-full"
|
||||
src={`/images/daily/${testimonial.image}`}
|
||||
width="75"
|
||||
/>
|
||||
</div>
|
||||
</article>
|
||||
))}
|
||||
</div>
|
||||
</section>
|
||||
)}
|
||||
</div>
|
||||
|
||||
<AboutMe />
|
||||
</div>
|
||||
39
src/pages/drupal-consulting.mdx
Normal file
39
src/pages/drupal-consulting.mdx
Normal file
|
|
@ -0,0 +1,39 @@
|
|||
---
|
||||
layout: ~/layouts/PageLayout.astro
|
||||
title: Oliver Davies - PHP Developer and Drupal Specialist
|
||||
---
|
||||
|
||||
export const email = "oliver@oliverdavies.uk"
|
||||
|
||||
I'm a long-time Web Developer and consultant. I’ve led, delivered, and maintained PHP, Drupal, and Drupal Commerce based websites, have worked for some of the UK’s largest and well-known PHP and Drupal agencies, and even for the Drupal Association - the nonprofit organisation behind the Drupal project - where I was employed to work on and improve the Drupal.org websites.
|
||||
|
||||
<a href={`mailto:${email}`}>Send me an email</a> to discuss your project.
|
||||
|
||||
## My Drupal Experience
|
||||
|
||||
I have contributed code to Drupal core and to various other Drupal modules, and maintain modules and themes like Override Node Options which is used on over 30, 000 Drupal sites according to Drupal.org. I’ve been a mentor at various in-person events, helping new contributors to the Drupal project, and regularly write blog posts, present talks and workshops, and create videos and live streams.
|
||||
|
||||
As well as Drupal, I’ve worked with other PHP projects like Symfony and Laravel, static site generators like Sculpin and Jekyll, and JavaScript frameworks such as Vue.js and Angular.
|
||||
|
||||
## Certifications
|
||||
|
||||
- Acquia certified Developer - Drupal 8 (2017)
|
||||
- Acquia certified Back-End Specialist - Drupal 8 (2017)
|
||||
- Acquia certified Front-End Specialist - Drupal 8 (2017)
|
||||
- Acquia certified Cloud Pro (2018)
|
||||
- Platform.sh Gold partner certification (2021, for Inviqa)
|
||||
|
||||
## Community contributions
|
||||
|
||||
- Authored an article on Drupal development using distributions for Linux Journal's Drupal issue.
|
||||
- Mentored new contributors at DrupalCon contribution days with their first patches to Drupal core.
|
||||
- Organised the Drupal Bristol and PHP South West (PHPSW) user groups, and the DrupalCamp Bristol conference.
|
||||
- Currently organise and sponsor the [PHP South Wales user group](https://www.phpsouthwales.uk).
|
||||
- Board member for the [Drupal England and Wales Association](https://drupal-england-wales.github.io) (2020 to present).
|
||||
- Selecting sessions for DrupalCon Europe 2021 as part of the DrupalCon track team.
|
||||
- Mentored students on the DrupalEasy [Drupal Career Online](https://www.drupaleasy.com/academy/dco/course-information) course.
|
||||
- Currently writing "Test-Driven Drupal", an eBook about automated testing and test-driven development in Drupal.
|
||||
|
||||
## Podcasts
|
||||
|
||||
I've been a guest on a number of podcasts, including [Talking Drupal](https://talkingdrupal.com), [How to Code Well](https://howtocodewell.fm), [That Podcast](https://thatpodcast.io), and [Voices of the ElePHPant](https://voicesoftheelephpant.com), where I've discussed topics including PHP, Drupal, CSS frameworks, and automated testing.
|
||||
74
src/pages/drupal-testing.mdx
Normal file
74
src/pages/drupal-testing.mdx
Normal file
|
|
@ -0,0 +1,74 @@
|
|||
---
|
||||
layout: ~/layouts/PageLayout.astro
|
||||
title: Introduction to Automated Testing and Test-Driven Development with Drupal
|
||||
---
|
||||
|
||||
export const drupalVersions = '9 and 10'
|
||||
|
||||
export const prices = {
|
||||
early: "395.00",
|
||||
full: "495.00",
|
||||
}
|
||||
|
||||
export const isEarlyBird = true
|
||||
|
||||
export const nextDate = '2022-04-04'
|
||||
|
||||
export const testimonials = [
|
||||
{
|
||||
name: 'Scott Euser, Head of Web Development',
|
||||
image: '/images/scott-euser.jpg',
|
||||
text: 'Oliver really knows his stuff. Whether you are just starting out or looking to take your knowledge to the next level, his patient and clear way of explaining will help get you there.',
|
||||
},
|
||||
]
|
||||
|
||||
Are you a Drupal Developer who wants to learn about automated testing and test-driven development, or do you manage a development team that you'd like to train?
|
||||
|
||||
I've delivered large Drupal projects using automated tests and test-driven development for custom functionality, and maintain Drupal modules with thousands of installations whilst using their tests to ensure working code and prevent regressions.
|
||||
|
||||
I offer an interactive full-day workshop (previously presented at DrupalCamp London, and remotely for DrupalCamp NYC) that provides an introduction to automated testing in Drupal and how to utilise test-driven development - which I've updated specifically for Drupal {drupalVersions}.
|
||||
|
||||
## Contents
|
||||
|
||||
* What is automated testing, and why write tests?
|
||||
* What types of tests are available in Drupal?
|
||||
* Outside-in vs. inside-out testing.
|
||||
* Configuring Drupal and PHPUnit to run tests locally.
|
||||
* Exercise: writing tests for existing Drupal core functionality.
|
||||
* Exercise: adding tests to an existing custom module.
|
||||
* What is test-driven development?
|
||||
* Exercise: writing a new Drupal module from scratch with test-driven development.
|
||||
* Q&A
|
||||
|
||||
<hr />
|
||||
|
||||
## Dates and prices
|
||||
|
||||
The workshop is currently only available remotely, and the next available date is <span class="font-bold">{new Date(nextDate).toLocaleDateString('en-GB', { day: 'numeric', month: 'long', year: 'numeric', })}</span>.
|
||||
|
||||
Seats are available at <span class="font-bold">{isEarlyBird ? `an early bird price of £${prices.early}` : `a price of £${prices.full}`}</span>, with a 10% discount for bulk orders of 5 or more seats.
|
||||
|
||||
<div class="mt-6">
|
||||
<a class="inline-flex items-center px-6 py-3 font-medium rounded-md bg-blue-primary text-white no-underline hover:bg-white hover:text-blue-primary focus:bg-white focus:text-blue-primary transition-color ease-in-out duration-200 text-base" href="https://buy.stripe.com/6oE3cW4Su7DA1t6144">
|
||||
Book your seat →
|
||||
</a>
|
||||
</div>
|
||||
|
||||
<hr />
|
||||
|
||||
## Testimonials
|
||||
|
||||
{testimonials.map(testimonial => (
|
||||
<div>
|
||||
<blockquote class="mt-4">
|
||||
{testimonial.text}
|
||||
</blockquote>
|
||||
|
||||
<footer class="flex items-center space-x-4 space-x-reverse">
|
||||
<span class="text-base">{testimonial.name}</span>
|
||||
<span class="order-first">
|
||||
<img width="40" height="40" class="w-10 h-10 rounded-full border" src={testimonial.image} />
|
||||
</span>
|
||||
</footer>
|
||||
</div>
|
||||
))}
|
||||
23
src/pages/index.md
Normal file
23
src/pages/index.md
Normal file
|
|
@ -0,0 +1,23 @@
|
|||
---
|
||||
layout: ~/layouts/PageLayout.astro
|
||||
title: Oliver Davies - Software Developer and Consultant, PHP and Drupal specialist
|
||||
---
|
||||
|
||||
<div class="mb-4 w-32">
|
||||
<img src="/images/social-avatar.jpg" alt="Picture of Oliver" class="rounded-full border border-gray">
|
||||
</div>
|
||||
|
||||
Hi, I’m Oliver. I’m a Full Stack Software Consultant based in South Wales in the UK.
|
||||
|
||||
I architect, develop, and consult on large web applications, and work with organisations, agencies, and freelance Developers to improve their code quality by using tools and workflows such as continuous integration and deployment, automated testing, test-driven development, and static analysis.
|
||||
|
||||
I have years of software development and Drupal experience, have worked for the Drupal Association, and am an <a href="https://certification.acquia.com/user/4540">Acquia-certified Drupal expert</a>. I also work with complementary technologies such as Symfony, Vue.js, TypeScript, Docker, and Ansible.
|
||||
|
||||
I enjoy writing and contributing open-source code which you can find on my [Drupal.org] and [GitHub] profiles.
|
||||
|
||||
I regularly <a href="/talks">present talks and workshops</a> at user groups and conferences and am the organiser of the <a href="https://www.phpsouthwales.uk">PHP South Wales</a> user group.
|
||||
|
||||
<a href="/contact">Contact me</a> if you’d like any more information or to discuss a project.
|
||||
|
||||
[drupal.org]: https://drupal.org/u/opdavies
|
||||
[github]: https://github.com/opdavies
|
||||
29
src/pages/links.mdx
Normal file
29
src/pages/links.mdx
Normal file
|
|
@ -0,0 +1,29 @@
|
|||
---
|
||||
layout: ~/layouts/PageLayout.astro
|
||||
title: Links
|
||||
---
|
||||
|
||||
export const links = [
|
||||
{ title: 'My daily email list', url: '/daily' },
|
||||
{ title: 'Twitter', url: 'https://twitter.com/opdavies' },
|
||||
{ title: 'YouTube', url: 'https://www.youtube.com/channel/UCkeK0qF9HHUPQH_fvn4ghqQ' },
|
||||
{ title: 'LinkedIn', url: 'https://www.linkedin.com/in/opdavies' },
|
||||
{ title: 'Drupal.org', url: 'https://www.drupal.org/u/opdavies' },
|
||||
{ title: 'GitHub', url: 'https://github.com/opdavies' },
|
||||
{ title: 'GitHub Gists', url: 'https://gist.github.com/opdavies' },
|
||||
{ title: 'Packagist', url: 'https://packagist.org/packages/opdavies' },
|
||||
{ title: 'Speakerdeck', url: 'https://speakerdeck.com/opdavies' },
|
||||
{ title: 'PHP South Wales', url: 'https://www.phpsouthwales.uk' },
|
||||
];
|
||||
|
||||
<div class="mx-auto max-w-md">
|
||||
<ul class="p-0 space-y-4 list-none">
|
||||
{links && links.map(link => (
|
||||
<li>
|
||||
<a class="block p-2 w-full text-center text-black no-underline border transition duration-200 ease-in-out dark:text-white hover:text-white focus:text-white dark:hover:text-black dark:focus:text-black dark:hover:bg-white dark:focus:bg-white hover:bg-blue-primary focus:bg-blue-primary" href={link.url}>
|
||||
{link.title}
|
||||
</a>
|
||||
</li>
|
||||
))}
|
||||
</ul>
|
||||
</div>
|
||||
18
src/pages/pair.mdx
Normal file
18
src/pages/pair.mdx
Normal file
|
|
@ -0,0 +1,18 @@
|
|||
---
|
||||
layout: ~/layouts/PageLayout.astro
|
||||
title: Pair program with me
|
||||
---
|
||||
|
||||
I enjoy pair and mob (group) programming, so as well as [traditional freelance
|
||||
services][0], I offer paid remote pair programming sessions where I'll work
|
||||
with you on your own project via a Zoom call.
|
||||
|
||||
My experience is based around PHP, Drupal, Symfony, Vue.js, Tailwind CSS,
|
||||
Ansible, Docker, clean code, automated testing, and test-driven development.
|
||||
|
||||
I also offer free sessions for open source projects.
|
||||
|
||||
To arrange a pairing session, [find an available time on my calendar][1].
|
||||
|
||||
[0]: /drupal-php-developer
|
||||
[1]: https://savvycal.com/opdavies/pair
|
||||
52
src/pages/search.astro
Normal file
52
src/pages/search.astro
Normal file
|
|
@ -0,0 +1,52 @@
|
|||
---
|
||||
import PageLayout from "~/layouts/PageLayout.astro";
|
||||
|
||||
const commonSearches = [
|
||||
"Drupal",
|
||||
"Test-Driven Development",
|
||||
"Tailwind CSS",
|
||||
"Ansible",
|
||||
"Ansistrano",
|
||||
];
|
||||
---
|
||||
|
||||
<PageLayout title="Search">
|
||||
<div>
|
||||
<form
|
||||
class="flex items-center space-x-6"
|
||||
action="https://www.google.com/search"
|
||||
method="get"
|
||||
>
|
||||
<div class="flex-1">
|
||||
<input
|
||||
type="hidden"
|
||||
name="q"
|
||||
value="site:https://www.oliverdavies.uk"
|
||||
/>
|
||||
<input class="w-full" type="text" name="q" alt="search" />
|
||||
</div>
|
||||
|
||||
<div>
|
||||
<input class="button cursor-pointer" type="submit" value="Search" />
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
|
||||
<aside>
|
||||
<h2>Common searches</h2>
|
||||
|
||||
<ul>
|
||||
{
|
||||
commonSearches.map((search) => (
|
||||
<li>
|
||||
<a
|
||||
href={`https://www.google.com/search?q=site%3Awww.oliverdavies.uk+%22${search}%22`}
|
||||
>
|
||||
{search}
|
||||
</a>
|
||||
</li>
|
||||
))
|
||||
}
|
||||
</ul>
|
||||
</aside>
|
||||
</PageLayout>
|
||||
34
src/pages/speaker-information.mdx
Normal file
34
src/pages/speaker-information.mdx
Normal file
|
|
@ -0,0 +1,34 @@
|
|||
---
|
||||
layout: ~/layouts/PageLayout.astro
|
||||
title: Speaker Information
|
||||
---
|
||||
|
||||
## Bio
|
||||
|
||||
<a href="https://www.oliverdavies.uk">Oliver Davies</a> (<a href="https://twitter.com/opdavies">@opdavies</a>) has been building websites since 2007, and speaking at meetups and conferences since 2012. He is a Full Stack Developer and a certified Drupal expert who also has experience developing with Symfony, Laravel, Sculpin and Vue.js, as well as with DevOps and systems administration.
|
||||
|
||||
He is a Lead Software Developer at <a href="https://tfw.wales/?%20utm_source=oliverdavies.uk&utm_medium=speaker-information">Transport for Wales</a>, 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 organises the PHP South Wales user group.
|
||||
|
||||
## Photos
|
||||
|
||||
- https://www.dropbox.com/s/say1muiqedik0l4/0188395_thumb.jpg
|
||||
|
||||
## Some events that I’ve spoken at
|
||||
|
||||
- BlueConf 2019 (Cardiff, UK)
|
||||
- DrupalCamp Brighton 2015
|
||||
- DrupalCamp Bristol 2016
|
||||
- DrupalCamp Dublin 2017
|
||||
- DrupalCamp London (2014, 2015, 2016, 2017, 2019, 2020)
|
||||
- DrupalCamp North 2015 (Sunderland, UK)
|
||||
- DrupalCon Amsterdam 2019
|
||||
- DrupalCon Europe 2020 (Online)
|
||||
- Nomad PHP
|
||||
- PHP North West 2017 (Manchester, UK - 10 year anniversary)
|
||||
- PHP South Coast 2016 (Portsmouth, UK)
|
||||
- PHP UK Conference 2018 (London, UK)
|
||||
- WordCamp Bristol 2019
|
||||
|
||||
I also [gave a number of talks remotely](/blog/speaking-remotely-during-lockdown) for various user groups and conferences during COVID-19.
|
||||
41
src/pages/talks/[slug].astro
Normal file
41
src/pages/talks/[slug].astro
Normal file
|
|
@ -0,0 +1,41 @@
|
|||
---
|
||||
import AboutMe from "~/components/AboutMe.astro";
|
||||
import Events from "~/components/talk/Events.astro";
|
||||
import Layout from "~/layouts/Layout.astro";
|
||||
import Markdown from "~/components/Markdown.astro";
|
||||
import Slides from "~/components/talk/Slides.astro";
|
||||
import Video from "~/components/talk/Video.astro";
|
||||
import { getSlugFromFile } from "~/utils.ts";
|
||||
|
||||
export async function getStaticPaths() {
|
||||
const talks = await Astro.glob("../../talks/*.md");
|
||||
|
||||
return talks.map((talk) => {
|
||||
const slug = getSlugFromFile(talk.file);
|
||||
|
||||
return {
|
||||
params: { slug },
|
||||
props: { talk },
|
||||
};
|
||||
});
|
||||
}
|
||||
|
||||
const { Content } = Astro.props.talk;
|
||||
const { events, speakerdeck, title, video } = Astro.props.talk.frontmatter;
|
||||
---
|
||||
|
||||
<Layout title={title}>
|
||||
<div class="space-y-6">
|
||||
<Markdown>
|
||||
<Content />
|
||||
</Markdown>
|
||||
|
||||
{speakerdeck && <Slides id={speakerdeck.id} ratio={speakerdeck.ratio} />}
|
||||
|
||||
{video && <Video id={video.id} type={video.type} />}
|
||||
|
||||
<Events events={events} />
|
||||
|
||||
<AboutMe />
|
||||
</div>
|
||||
</Layout>
|
||||
37
src/pages/talks/index.astro
Normal file
37
src/pages/talks/index.astro
Normal file
|
|
@ -0,0 +1,37 @@
|
|||
---
|
||||
import PageLayout from "~/layouts/PageLayout.astro";
|
||||
import _ from "lodash";
|
||||
import { getSlugFromFile } from "~/utils.ts";
|
||||
import ListingPage from "~/components/ListingPage.astro";
|
||||
|
||||
const talks = await Astro.glob("../../talks/*.md");
|
||||
|
||||
const talkCount = _(talks)
|
||||
.flatMap((talk) => talk.frontmatter.events)
|
||||
.size();
|
||||
|
||||
const sortedTalks = talks
|
||||
.map((talk) => {
|
||||
const slug = `/talks/${getSlugFromFile(talk.file)}`;
|
||||
|
||||
return { slug, item: talk };
|
||||
})
|
||||
.sort((b, a) => {
|
||||
const events = [
|
||||
a.item.frontmatter.events[a.item.frontmatter.events.length - 1],
|
||||
b.item.frontmatter.events[b.item.frontmatter.events.length - 1],
|
||||
];
|
||||
|
||||
return (
|
||||
new Date(events[0].date).valueOf() - new Date(events[1].date).valueOf()
|
||||
);
|
||||
});
|
||||
---
|
||||
|
||||
<ListingPage items={sortedTalks} title="Talks and workshops">
|
||||
<p slot="intro">
|
||||
Starting with my first talk in September 2012, I have given {talkCount} presentations
|
||||
and workshops at various conferences and meetups, in-person and remotely, on
|
||||
topics including PHP, Drupal, automated testing, Git, CSS, and systems administration.
|
||||
</p>
|
||||
</ListingPage>
|
||||
62
src/pages/things-about-php.mdx
Normal file
62
src/pages/things-about-php.mdx
Normal file
|
|
@ -0,0 +1,62 @@
|
|||
---
|
||||
layout: ~/layouts/PageLayout.astro
|
||||
title: Things you should know about PHP
|
||||
---
|
||||
|
||||
export const email = "oliver@oliverdavies.uk"
|
||||
|
||||
Thanks for attending my [Things you should know about PHP](/talks/things-you-should-know-about-php) talk.
|
||||
|
||||
I hope that you learned some things about PHP, its ecosystem, and its communities, and if you haven't tried using PHP yet, I'd encourage you to do so.
|
||||
|
||||
Here are links to the resources that I mention in the talk, plus a couple of extras.
|
||||
|
||||
## Resources
|
||||
|
||||
- [The PHP Foundation](https://thephp.foundation) - non-profit to support, advance, and develop the PHP language
|
||||
- [PHP-FIG](https://www.php-fig.org) - PHP Framework Interop Group
|
||||
- [Composer](https://getcomposer.org) - dependency manager
|
||||
- [Drupal](https://www.drupal.org) - content management system
|
||||
- [Jigsaw](https://jigsaw.tighten.co) - static site generator
|
||||
- [Laravel](https://laravel.com) - framework
|
||||
- [Nomad PHP](https://nomadphp.com) - online user group
|
||||
- [PHP official images on Docker Hub](https://hub.docker.com/_/php)
|
||||
- [PHPStan](https://phpstan.org) - static analysis tool
|
||||
- [PHPUnit](https://phpunit.de) - testing framework
|
||||
- [Pest](https://pestphp.com) - testing framework
|
||||
- [Psalm](https://psalm.dev) - static analysis tool
|
||||
- [Sculpin](khttps://sculpin.io) - static site generator
|
||||
- [WordPress](https://wordpress.org) - content management system
|
||||
- [php.net](https://www.php.net) - online documentation
|
||||
- [php[architect]](https://www.phparch.com) - online magazine
|
||||
|
||||
## Books
|
||||
|
||||
- [Laravel: Up & Running](https://www.oreilly.com/library/view/laravel-up/9781492041207)
|
||||
- [Symfony: The Fast Track](https://symfony.com/book)
|
||||
|
||||
## Videos
|
||||
|
||||
- [Codecourse](https://codecourse.com)
|
||||
- [How to Code Well](https://www.howtocodewell.net)
|
||||
- [Laracasts](https://laracasts.com)
|
||||
- [SymfonyCasts](https://symfonycasts.com)
|
||||
|
||||
## Podcasts
|
||||
|
||||
- [How to Code Well podcast](https://howtocodewell.fm)
|
||||
- [PHPUgly](https://www.phpugly.com)
|
||||
- [Talking Drupal](https://talkingdrupal.com)
|
||||
- [The Laravel Podcast](https://laravelpodcast.com)
|
||||
- [The PHP Roundtable](https://phproundtable.com)
|
||||
- [Voices of the elePHPant](https://voicesoftheelephpant.com)
|
||||
|
||||
## Can I help?
|
||||
|
||||
Do you want to introduce PHP to your company or team, or add one of these tools to your existing PHP application?
|
||||
|
||||
I offer consulting calls and services to reduce your onboarding time and get you up and running quicker and easier.
|
||||
|
||||
<div class="mt-6">
|
||||
<a class="inline-flex items-center px-6 py-3 font-medium rounded-md bg-blue-primary text-white no-underline hover:bg-white hover:text-blue-primary focus:bg-white focus:text-blue-primary transition-color ease-in-out duration-200 text-base" href={`mailto:${email}?subject=Book in my call`}>Book in your call →</a>
|
||||
</div>
|
||||
Loading…
Add table
Add a link
Reference in a new issue