@@ -3,7 +3,7 @@
|
||||
<div class="flex flex-col min-h-screen fade-in">
|
||||
<NavBar/>
|
||||
|
||||
<div class="flex-1 px-4 md:px-12 py-4">
|
||||
<div class="flex-1 px-4 md:px-12 lg:px-24 xl:px-32 py-4">
|
||||
@Body
|
||||
</div>
|
||||
|
||||
|
||||
@@ -4,14 +4,7 @@
|
||||
|
||||
<PageTitle>About - Beau Findlay</PageTitle>
|
||||
|
||||
@if (comingSoon)
|
||||
{
|
||||
<div class="text-center">
|
||||
<h1 class="text-4xl">Coming soon...</h1>
|
||||
</div>
|
||||
}
|
||||
else
|
||||
{
|
||||
<div class="text-center pb-4" id="@TopSection">
|
||||
@if (!hasPreviouslyRendered)
|
||||
{
|
||||
<h1 class="text-4xl">
|
||||
@@ -20,33 +13,62 @@ else
|
||||
}
|
||||
else
|
||||
{
|
||||
<h1 class="text-4xl">This app<span class="blinking-cursor">|</span></h1>
|
||||
<h1 class="text-4xl">This app</h1>
|
||||
}
|
||||
</div>
|
||||
|
||||
<p class="py-4 text-xl">Below is a brief outline of how this app is made and what technologies are used. If you'd like to dive straight in then full project is available on my <Anchor Href="https://github.com/bdfin/my-portfolio">GitHub</Anchor>.</p>
|
||||
<nav class="flex items-center justify-center py-8 space-x-8">
|
||||
<a @onclick="() => ScrollToElementAsync(FrontEndSection)" class="underline underline-offset-2 cursor-pointer">Front-end</a>
|
||||
<a @onclick="() => ScrollToElementAsync(BackEndSection)" class="underline underline-offset-2 cursor-pointer">Back-end</a>
|
||||
<a @onclick="() => ScrollToElementAsync(HostingSection)" class="underline underline-offset-2 cursor-pointer">Hosting</a>
|
||||
</nav>
|
||||
|
||||
<section class="py-6" id="@FrontEndSection">
|
||||
<h2 class="text-2xl">Front-end</h2>
|
||||
<p class="py-4 text-xl">Below is an overview of how this simple app is made and what technologies are used. If you'd like to dive straight in, the full project is available on my <Anchor Href="https://github.com/bdfin/my-portfolio">GitHub</Anchor>.</p>
|
||||
|
||||
<p class="pt-4 pb-8 text-xl">I'm planning to integrate a simple blog as part of this app that will dive into more specific implementation details so check back soon for more!</p>
|
||||
|
||||
<section class="py-12 text-lg" id="@FrontEndSection">
|
||||
<h2 class="text-3xl pb-4">Front-end: <img src="images/blazor-logo.png" class="inline w-auto h-6" alt="blazor logo"/> .NET Blazor WASM</h2>
|
||||
|
||||
<p class="py-4">I wanted to create a decent, modern client-side experience for this app and given my <em class="text-xs">(very...)</em> limited front-end expertise I decided to choose <Anchor Href="https://dotnet.microsoft.com/en-us/apps/aspnet/web-apps/blazor">.NET Blazor Webassembly</Anchor>. Blazor is Microsoft's take on component-based SPAs (single page applications) and offers us back-end focussed devs a way of producing decent client experiences without needing to dive into another front-end specific technology.</p>
|
||||
|
||||
<p class="py-4">Blazor traditionally came in two flavours, server and webassembly with an additional third option (Blazor Web App) recently released with .NET 8 which is an amalgamation of both. <Anchor Href="https://learn.microsoft.com/en-us/aspnet/core/blazor/hosting-models?view=aspnetcore-8.0#blazor-server">Blazor Server</Anchor> initially generates content on the server and utilises web-sockets to communicate dynamic UI updates with the client without requiring a page load, whereas <Anchor Href="https://learn.microsoft.com/en-us/aspnet/core/blazor/hosting-models?view=aspnetcore-8.0#blazor-webassembly">Blazor Webassembly</Anchor> downloads the entire app to the client browser on first load alongside a light-weight .NET run-time to execute code directly on the browsers UI thread.</p>
|
||||
<p class="py-4">Blazor traditionally came in two flavours, server and webassembly with an additional third option (Blazor Web App) recently released with .NET 8 which can offer the functionality of both, alongside traditional SSR (server-side rendering). <Anchor Href="https://learn.microsoft.com/en-us/aspnet/core/blazor/hosting-models?view=aspnetcore-8.0#blazor-server">Blazor Server</Anchor> initially generates content on the server and utilises web-sockets to communicate dynamic UI updates with the client without requiring a page load, whereas <Anchor Href="https://learn.microsoft.com/en-us/aspnet/core/blazor/hosting-models?view=aspnetcore-8.0#blazor-webassembly">Blazor Webassembly</Anchor> downloads the entire app to the client browser on first load alongside a light-weight .NET run-time to execute code directly on the browsers UI thread.</p>
|
||||
|
||||
<p class="py-4">As Blazor server requires a dedicated server to host the application, I chose Blazor webassembly to enable me to host this app for free using an <Anchor Href="https://azure.microsoft.com/en-gb/products/app-service/static">Azure Static Web App</Anchor>. You can read more about this in the <a @onclick="() => ScrollToElementAsync(HostingSection)" class="underline underline-offset-2 cursor-pointer">hosting</a> section.</p>
|
||||
</section>
|
||||
<p class="py-4">As Blazor server requires a dedicated server to host the application, I chose the webassembly model to enable free hosting using an <Anchor Href="https://azure.microsoft.com/en-gb/products/app-service/static">Azure Static Web App</Anchor>. You can read more about this in the <a @onclick="() => ScrollToElementAsync(HostingSection)" class="underline underline-offset-2 cursor-pointer">hosting</a> section.</p>
|
||||
|
||||
<section class="py-6" id="@BackEndSection">
|
||||
<h2 class="text-2xl pb-4">Back-end</h2>
|
||||
<p class="my-4">As the </p>
|
||||
</section>
|
||||
<p class="py-4">This app is styled using a cool CSS framework called <Anchor Href="https://tailwindcss.com/">TailwindCSS</Anchor>. <Anchor Href="https://postcss.org/">PostCSS</Anchor> is used alongside Tailwind to generate a lightweight stylesheet based only on the parts of the framework that are used, as oppose to including a everything the framework offers.</p>
|
||||
</section>
|
||||
|
||||
<section class="py-12 text-lg" id="@BackEndSection">
|
||||
<h2 class="text-3xl pb-4">Back-end: <img src="images/azure-function-logo.png" class="inline w-auto h-6" alt="azure function app logo"/> .NET Azure Functions API</h2>
|
||||
|
||||
<p class="py-4">There is a very minimal API used as the back-end of this app to allow users to contact me directly via the <NavLink href="/contact" class="underline underline-offset-2">contact</NavLink> page. This will be expanded to serve the technical blog I'm building as a new feature that will be available soon.</p>
|
||||
|
||||
<p class="pt-4 pb-2">The contact API endpoint currently:</p>
|
||||
<ul class="list-disc pl-8 pb-4">
|
||||
<li>Validates a <Anchor Href="https://www.google.com/recaptcha/about/">Google Recaptcha</Anchor> token to protect against fraudulent submissions.</li>
|
||||
<li>Builds a HTML email from the information provided in the form.</li>
|
||||
<li>Sends an email directly to my inbox using the <Anchor Href="https://sendgrid.com/en-us">SendGrid</Anchor> API.</li>
|
||||
</ul>
|
||||
|
||||
<p class="py-4">The API is written in .NET 8 using <Anchor Href="https://azure.microsoft.com/en-gb/products/functions">Azure Serverless Functions</Anchor> with HTTP triggers to act as API endpoints. For larger scale projects I would almost always opt for a fully-featured <Anchor Href="https://dotnet.microsoft.com/en-us/apps/aspnet/apis">Web API</Anchor>, however Azure Functions provide automatic elastic scaling with consumption-based billing and a generous free-tier, making them perfect for smaller projects like this.</p>
|
||||
|
||||
</section>
|
||||
|
||||
|
||||
<section class="py-6" id="@HostingSection">
|
||||
<h2 class="text-2xl pb-4">Hosting</h2>
|
||||
<p></p>
|
||||
</section>
|
||||
}
|
||||
<section class="py-12 text-lg" id="@HostingSection">
|
||||
<h2 class="text-3xl pb-4">Hosting: <img src="images/azure-static-web-app-logo.png" class="inline w-auto h-6" alt="azure static web app logo"/> Microsoft Azure Static Web App</h2>
|
||||
|
||||
<p class="py-4">The goal of this project was to learn some new technologies and host the app as cheaply as possible. With this in mind I decided to go with a <Anchor Href="https://azure.microsoft.com/en-gb/products/app-service/static">Static Web App</Anchor> hosted on Microsoft Azure. Static Web Apps offer global distribution of static assets (the Blazor Webassembly app in this case) and offer integrated hosting for Azure Function App APIs.</p>
|
||||
|
||||
<p class="py-4">Another cool feature of Static Web Apps is Azure's integration with GitHub actions to deploy both the client and server simultaneously and provide automatically deployed staging environments for pull-requests opened to the main branch. This made testing deployed changes much easier and cheaper than deploying an isolated testing/GA environment before releasing to the live version of the app.</p>
|
||||
|
||||
<p class="py-4">Using Static Web Apps on Azure has meant that I have been able to build, deploy and serve this site and API completely free (with the exception of the domain name). The next thing on the roadmap is building a simple blog using an <Anchor Href="https://azure.microsoft.com/en-gb/products/azure-sql/database">Azure SQL database</Anchor> where I'll document the full process of writing and deploying this app so check back again soon.</p>
|
||||
</section>
|
||||
|
||||
<nav class="flex items-center justify-center pb-8">
|
||||
<a @onclick="() => ScrollToElementAsync(TopSection)" class="underline underline-offset-2 cursor-pointer">Top</a>
|
||||
</nav>
|
||||
|
||||
<AnchorNavigation/>
|
||||
|
||||
@@ -55,9 +77,9 @@ else
|
||||
private const string FrontEndSection = "front-end";
|
||||
private const string BackEndSection = "back-end";
|
||||
private const string HostingSection = "hosting";
|
||||
private const string TopSection = "top";
|
||||
|
||||
private bool hasPreviouslyRendered;
|
||||
private bool comingSoon = true;
|
||||
|
||||
protected override async Task OnAfterRenderAsync(bool firstRender)
|
||||
{
|
||||
|
||||
@@ -1,7 +1,5 @@
|
||||
@page "/"
|
||||
|
||||
@implements IDisposable
|
||||
|
||||
@inject IJSRuntime JSRuntime
|
||||
|
||||
<PageTitle>Home - Beau Findlay</PageTitle>
|
||||
@@ -12,19 +10,19 @@
|
||||
<Typewriter Text="Hi, I'm Beau."/>
|
||||
</h1>
|
||||
|
||||
<p class="text-xl mt-4">
|
||||
<p class="text-xl py-4">
|
||||
<Typewriter Name="@TypewriterConstants.Name.IntroComplete" Text="I'm a UK-based software engineer and I love building cool stuff."/>
|
||||
</p>
|
||||
|
||||
<h2 class="text-2xl mt-16 font-semibold">
|
||||
<h2 class="text-2xl pt-16 font-semibold">
|
||||
<Typewriter Text="A bit about me"/>
|
||||
</h2>
|
||||
|
||||
<p class="text-xl mt-4">
|
||||
<p class="text-xl py-4">
|
||||
<Typewriter Text="I mostly specialise in back-end C#/.NET development and I've built systems that scale for hundreds-of-thousands of global users."/>
|
||||
</p>
|
||||
|
||||
<p class="text-xl mt-4">
|
||||
<p class="text-xl py-4">
|
||||
<Typewriter Text="I've worked with businesses at all sizes and stages and I'm currently heading up the tech as CTO at a cool startup called un:hurd."/>
|
||||
</p>
|
||||
}
|
||||
@@ -32,13 +30,13 @@ else
|
||||
{
|
||||
<h1 class="text-4xl">Hi, I'm Beau.</h1>
|
||||
|
||||
<p class="text-xl mt-4">I'm a UK-based software engineer and I love building cool stuff.</p>
|
||||
<p class="text-xl py-4">I'm a UK-based software engineer and I love building cool stuff.</p>
|
||||
|
||||
<h2 class="text-3xl mt-16 font-semibold">A bit about me</h2>
|
||||
<h2 class="text-3xl pt-16 font-semibold">A bit about me</h2>
|
||||
|
||||
<p class="text-xl mt-4">I mostly specialise in back-end C#/.NET development and I've built systems that scale for hundreds-of-thousands of global users.</p>
|
||||
<p class="text-xl py-4">I mostly specialise in back-end C#/.NET development and I've built systems that scale for hundreds-of-thousands of global users.</p>
|
||||
|
||||
<p class="text-xl mt-4">I've worked with businesses at all sizes and stages and I'm currently heading up the tech as CTO at a cool startup called <Anchor Href="https://unhurd.co.uk">un:hurd</Anchor>.</p>
|
||||
<p class="text-xl py-4">I've worked with businesses at all sizes and stages and I'm currently heading up the tech as CTO at a cool startup called <Anchor Href="https://unhurd.co.uk">un:hurd</Anchor>.</p>
|
||||
}
|
||||
|
||||
|
||||
@@ -50,8 +48,6 @@ else
|
||||
{
|
||||
if (firstRender)
|
||||
{
|
||||
Typewriter.OnAllTypingCompleted += HandleTypingCompleted;
|
||||
|
||||
var renderedBeforeAsString = await JSRuntime.InvokeAsync<string>("localStorage.getItem", ComponentKey);
|
||||
|
||||
var previousValue = hasPreviouslyRendered;
|
||||
@@ -69,14 +65,4 @@ else
|
||||
}
|
||||
}
|
||||
|
||||
private static void HandleTypingCompleted()
|
||||
{
|
||||
Console.WriteLine("Typewriter finished typing.");
|
||||
}
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
Typewriter.OnAllTypingCompleted -= HandleTypingCompleted;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -2,7 +2,11 @@
|
||||
module.exports = {
|
||||
content: ["./**/*.{razor,html,cshtml}"],
|
||||
theme: {
|
||||
extend: {},
|
||||
extend: {
|
||||
fontFamily: {
|
||||
cascadia: ["Cascadia Code", "mono-space"]
|
||||
}
|
||||
},
|
||||
},
|
||||
plugins: [],
|
||||
}
|
||||
@@ -2,6 +2,11 @@
|
||||
@tailwind components;
|
||||
@tailwind utilities;
|
||||
|
||||
@font-face {
|
||||
font-family: "Cascadia Code";
|
||||
src: url("../fonts/CascadiaCode.woff2");
|
||||
}
|
||||
|
||||
@keyframes blink {
|
||||
from, to { opacity: 1 }
|
||||
50% { opacity: 0 }
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
! tailwindcss v3.4.1 | MIT License | https://tailwindcss.com
|
||||
! tailwindcss v3.3.3 | MIT License | https://tailwindcss.com
|
||||
*/
|
||||
|
||||
/*
|
||||
@@ -32,11 +32,9 @@
|
||||
4. Use the user's configured `sans` font-family by default.
|
||||
5. Use the user's configured `sans` font-feature-settings by default.
|
||||
6. Use the user's configured `sans` font-variation-settings by default.
|
||||
7. Disable tap highlights on iOS
|
||||
*/
|
||||
|
||||
html,
|
||||
:host {
|
||||
html {
|
||||
line-height: 1.5;
|
||||
/* 1 */
|
||||
-webkit-text-size-adjust: 100%;
|
||||
@@ -46,14 +44,12 @@ html,
|
||||
-o-tab-size: 4;
|
||||
tab-size: 4;
|
||||
/* 3 */
|
||||
font-family: ui-sans-serif, system-ui, sans-serif, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol", "Noto Color Emoji";
|
||||
font-family: ui-sans-serif, system-ui, -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue", Arial, "Noto Sans", sans-serif, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol", "Noto Color Emoji";
|
||||
/* 4 */
|
||||
font-feature-settings: normal;
|
||||
/* 5 */
|
||||
font-variation-settings: normal;
|
||||
/* 6 */
|
||||
-webkit-tap-highlight-color: transparent;
|
||||
/* 7 */
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -125,10 +121,8 @@ strong {
|
||||
}
|
||||
|
||||
/*
|
||||
1. Use the user's configured `mono` font-family by default.
|
||||
2. Use the user's configured `mono` font-feature-settings by default.
|
||||
3. Use the user's configured `mono` font-variation-settings by default.
|
||||
4. Correct the odd `em` font sizing in all browsers.
|
||||
1. Use the user's configured `mono` font family by default.
|
||||
2. Correct the odd `em` font sizing in all browsers.
|
||||
*/
|
||||
|
||||
code,
|
||||
@@ -137,12 +131,8 @@ samp,
|
||||
pre {
|
||||
font-family: ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, "Liberation Mono", "Courier New", monospace;
|
||||
/* 1 */
|
||||
font-feature-settings: normal;
|
||||
/* 2 */
|
||||
font-variation-settings: normal;
|
||||
/* 3 */
|
||||
font-size: 1em;
|
||||
/* 4 */
|
||||
/* 2 */
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -569,11 +559,6 @@ video {
|
||||
margin-right: auto;
|
||||
}
|
||||
|
||||
.my-4 {
|
||||
margin-top: 1rem;
|
||||
margin-bottom: 1rem;
|
||||
}
|
||||
|
||||
.ml-3 {
|
||||
margin-left: 0.75rem;
|
||||
}
|
||||
@@ -638,6 +623,10 @@ video {
|
||||
height: 100%;
|
||||
}
|
||||
|
||||
.h-7 {
|
||||
height: 1.75rem;
|
||||
}
|
||||
|
||||
.min-h-screen {
|
||||
min-height: 100vh;
|
||||
}
|
||||
@@ -658,6 +647,10 @@ video {
|
||||
width: 2rem;
|
||||
}
|
||||
|
||||
.w-auto {
|
||||
width: auto;
|
||||
}
|
||||
|
||||
.w-full {
|
||||
width: 100%;
|
||||
}
|
||||
@@ -688,6 +681,10 @@ video {
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.list-disc {
|
||||
list-style-type: disc;
|
||||
}
|
||||
|
||||
.grid-cols-1 {
|
||||
grid-template-columns: repeat(1, minmax(0, 1fr));
|
||||
}
|
||||
@@ -799,30 +796,50 @@ video {
|
||||
padding-bottom: 1rem;
|
||||
}
|
||||
|
||||
.py-8 {
|
||||
padding-top: 2rem;
|
||||
padding-bottom: 2rem;
|
||||
}
|
||||
|
||||
.py-6 {
|
||||
padding-top: 1.5rem;
|
||||
padding-bottom: 1.5rem;
|
||||
}
|
||||
|
||||
.py-8 {
|
||||
padding-top: 2rem;
|
||||
padding-bottom: 2rem;
|
||||
.pb-2 {
|
||||
padding-bottom: 0.5rem;
|
||||
}
|
||||
|
||||
.pb-4 {
|
||||
padding-bottom: 1rem;
|
||||
}
|
||||
|
||||
.pb-8 {
|
||||
padding-bottom: 2rem;
|
||||
}
|
||||
|
||||
.pl-8 {
|
||||
padding-left: 2rem;
|
||||
}
|
||||
|
||||
.pt-4 {
|
||||
padding-top: 1rem;
|
||||
}
|
||||
|
||||
.pt-8 {
|
||||
padding-top: 2rem;
|
||||
}
|
||||
|
||||
.pt-16 {
|
||||
padding-top: 4rem;
|
||||
}
|
||||
|
||||
.text-center {
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.font-mono {
|
||||
font-family: ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, "Liberation Mono", "Courier New", monospace;
|
||||
.font-cascadia {
|
||||
font-family: Cascadia Code, mono-space;
|
||||
}
|
||||
|
||||
.text-2xl {
|
||||
@@ -935,10 +952,6 @@ video {
|
||||
box-shadow: var(--tw-ring-offset-shadow, 0 0 #0000), var(--tw-ring-shadow, 0 0 #0000), var(--tw-shadow);
|
||||
}
|
||||
|
||||
.outline {
|
||||
outline-style: solid;
|
||||
}
|
||||
|
||||
.ring-1 {
|
||||
--tw-ring-offset-shadow: var(--tw-ring-inset) 0 0 0 var(--tw-ring-offset-width) var(--tw-ring-offset-color);
|
||||
--tw-ring-shadow: var(--tw-ring-inset) 0 0 0 calc(1px + var(--tw-ring-offset-width)) var(--tw-ring-color);
|
||||
@@ -954,6 +967,12 @@ video {
|
||||
--tw-ring-color: rgb(209 213 219 / var(--tw-ring-opacity));
|
||||
}
|
||||
|
||||
@font-face {
|
||||
font-family: "Cascadia Code";
|
||||
|
||||
src: url("../fonts/CascadiaCode.woff2");
|
||||
}
|
||||
|
||||
@keyframes blink {
|
||||
from, to {
|
||||
opacity: 1
|
||||
@@ -1061,6 +1080,17 @@ body::-webkit-scrollbar-thumb {
|
||||
background-color: rgb(31 41 55 / var(--tw-bg-opacity));
|
||||
}
|
||||
|
||||
@media (prefers-color-scheme: dark) {
|
||||
.dark\:fill-gray-300 {
|
||||
fill: #d1d5db;
|
||||
}
|
||||
|
||||
.dark\:text-gray-600 {
|
||||
--tw-text-opacity: 1;
|
||||
color: rgb(75 85 99 / var(--tw-text-opacity));
|
||||
}
|
||||
}
|
||||
|
||||
@media (min-width: 640px) {
|
||||
.sm\:col-span-2 {
|
||||
grid-column: span 2 / span 2;
|
||||
@@ -1102,13 +1132,16 @@ body::-webkit-scrollbar-thumb {
|
||||
}
|
||||
}
|
||||
|
||||
@media (prefers-color-scheme: dark) {
|
||||
.dark\:fill-gray-300 {
|
||||
fill: #d1d5db;
|
||||
}
|
||||
|
||||
.dark\:text-gray-600 {
|
||||
--tw-text-opacity: 1;
|
||||
color: rgb(75 85 99 / var(--tw-text-opacity));
|
||||
@media (min-width: 1024px) {
|
||||
.lg\:px-24 {
|
||||
padding-left: 6rem;
|
||||
padding-right: 6rem;
|
||||
}
|
||||
}
|
||||
|
||||
@media (min-width: 1280px) {
|
||||
.xl\:px-32 {
|
||||
padding-left: 8rem;
|
||||
padding-right: 8rem;
|
||||
}
|
||||
}
|
||||
Binary file not shown.
Binary file not shown.
|
After Width: | Height: | Size: 8.5 KiB |
Binary file not shown.
|
After Width: | Height: | Size: 7.7 KiB |
Binary file not shown.
|
After Width: | Height: | Size: 19 KiB |
Binary file not shown.
|
Before Width: | Height: | Size: 423 B |
Binary file not shown.
|
Before Width: | Height: | Size: 862 B |
BIN
BeauFindlay/src/BeauFindlay.Client/wwwroot/images/logo.png
Normal file
BIN
BeauFindlay/src/BeauFindlay.Client/wwwroot/images/logo.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 12 KiB |
@@ -5,6 +5,14 @@
|
||||
<script id="cookieyes"
|
||||
type="text/javascript"
|
||||
src="https://cdn-cookieyes.com/client_data/a05e8ecc917e725a2226b46a/script.js"></script>
|
||||
<script async src="https://www.googletagmanager.com/gtag/js?id=G-958BPT37HR"></script>
|
||||
<script>
|
||||
window.dataLayer = window.dataLayer || [];
|
||||
function gtag(){dataLayer.push(arguments);}
|
||||
gtag('js', new Date());
|
||||
|
||||
gtag('config', 'G-958BPT37HR');
|
||||
</script>
|
||||
<meta charset="utf-8"/>
|
||||
<meta name="viewport"
|
||||
content="width=device-width, initial-scale=1.0"/>
|
||||
@@ -17,8 +25,7 @@
|
||||
<title>Beau Findlay</title>
|
||||
<base href="/"/>
|
||||
<link rel="apple-touch-icon" sizes="180x180" href="images/apple-touch-icon.png">
|
||||
<link rel="icon" type="image/png" sizes="32x32" href="images/favicon-32x32.png">
|
||||
<link rel="icon" type="image/png" sizes="16x16" href="images/favicon-16x16.png">
|
||||
<link rel="icon" type="image/png" href="images/logo.png">
|
||||
<link rel="manifest" href="/site.webmanifest">
|
||||
<link rel="stylesheet"
|
||||
href="css/app.min.css"/>
|
||||
@@ -29,7 +36,7 @@
|
||||
referrerpolicy="no-referrer"/>
|
||||
</head>
|
||||
|
||||
<body class="bg-black font-mono text-slate-50 min-h-screen antialiased">
|
||||
<body class="bg-black font-cascadia text-slate-50 min-h-screen antialiased">
|
||||
<div id="app"
|
||||
class="h-full">
|
||||
<div class="flex items-center justify-center text-2xl">
|
||||
|
||||
Reference in New Issue
Block a user