Compare commits
4 Commits
027c7b2abc
...
69792d4faf
Author | SHA1 | Date | |
---|---|---|---|
69792d4faf
|
|||
9617feed0c
|
|||
5852aa7ebd
|
|||
b43bf3860f
|
10
.vscode/extensions.json
vendored
10
.vscode/extensions.json
vendored
@@ -1,4 +1,10 @@
|
||||
{
|
||||
"recommendations": ["astro-build.astro-vscode"],
|
||||
"recommendations": [
|
||||
"astro-build.astro-vscode",
|
||||
"bradlc.vscode-tailwindcss",
|
||||
"unifiedjs.vscode-mdx",
|
||||
"esbenp.prettier-vscode",
|
||||
"dbaeumer.vscode-eslint"
|
||||
],
|
||||
"unwantedRecommendations": []
|
||||
}
|
||||
}
|
@@ -10,6 +10,10 @@ import mdx from "@astrojs/mdx";
|
||||
|
||||
import sitemap from "@astrojs/sitemap";
|
||||
|
||||
import robotsTxt from "astro-robots-txt";
|
||||
|
||||
import { transformerMetaHighlight } from "@shikijs/transformers";
|
||||
|
||||
// https://astro.build/config
|
||||
export default defineConfig({
|
||||
vite: {
|
||||
@@ -26,7 +30,25 @@ export default defineConfig({
|
||||
}
|
||||
},
|
||||
|
||||
integrations: [icon(), mdx(), sitemap()],
|
||||
integrations: [icon(), mdx(), sitemap(), robotsTxt()],
|
||||
|
||||
markdown: {
|
||||
shikiConfig: {
|
||||
transformers: [
|
||||
transformerMetaHighlight(),
|
||||
{
|
||||
pre(hast) {
|
||||
hast.properties["data-meta"] = this.options.meta?.__raw;
|
||||
hast.properties["data-code"] = this.source;
|
||||
}
|
||||
}
|
||||
],
|
||||
themes: {
|
||||
light: "github-light",
|
||||
dark: "github-dark"
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
site: "https://www.nathancummins.com.au",
|
||||
|
||||
|
50
package-lock.json
generated
50
package-lock.json
generated
@@ -18,6 +18,7 @@
|
||||
"@tailwindcss/vite": "^4.1.11",
|
||||
"astro": "^5.12.8",
|
||||
"astro-icon": "^1.1.5",
|
||||
"astro-robots-txt": "^1.0.0",
|
||||
"astro-seo-schema": "^5.1.0",
|
||||
"get-audio-duration": "^4.0.1",
|
||||
"schema-dts": "^1.1.5",
|
||||
@@ -25,6 +26,7 @@
|
||||
},
|
||||
"devDependencies": {
|
||||
"@cspell/dict-en-au": "^1.1.4",
|
||||
"@shikijs/transformers": "^3.9.2",
|
||||
"@types/howler": "^2.2.12",
|
||||
"@typescript-eslint/eslint-plugin": "^8.38.0",
|
||||
"@typescript-eslint/parser": "^8.38.0",
|
||||
@@ -2122,6 +2124,17 @@
|
||||
"@shikijs/types": "3.9.2"
|
||||
}
|
||||
},
|
||||
"node_modules/@shikijs/transformers": {
|
||||
"version": "3.9.2",
|
||||
"resolved": "https://registry.npmjs.org/@shikijs/transformers/-/transformers-3.9.2.tgz",
|
||||
"integrity": "sha512-MW5hT4TyUp6bNAgTExRYLk1NNasVQMTCw1kgbxHcEC0O5cbepPWaB+1k+JzW9r3SP2/R8kiens8/3E6hGKfgsA==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@shikijs/core": "3.9.2",
|
||||
"@shikijs/types": "3.9.2"
|
||||
}
|
||||
},
|
||||
"node_modules/@shikijs/types": {
|
||||
"version": "3.9.2",
|
||||
"resolved": "https://registry.npmjs.org/@shikijs/types/-/types-3.9.2.tgz",
|
||||
@@ -3115,6 +3128,16 @@
|
||||
"@iconify/utils": "^2.1.30"
|
||||
}
|
||||
},
|
||||
"node_modules/astro-robots-txt": {
|
||||
"version": "1.0.0",
|
||||
"resolved": "https://registry.npmjs.org/astro-robots-txt/-/astro-robots-txt-1.0.0.tgz",
|
||||
"integrity": "sha512-6JQSLid4gMhoWjOm85UHLkgrw0+hHIjnJVIUqxjU2D6feKlVyYukMNYjH44ZDZBK1P8hNxd33PgWlHzCASvedA==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"valid-filename": "^4.0.0",
|
||||
"zod": "^3.22.2"
|
||||
}
|
||||
},
|
||||
"node_modules/astro-seo-schema": {
|
||||
"version": "5.1.0",
|
||||
"resolved": "https://registry.npmjs.org/astro-seo-schema/-/astro-seo-schema-5.1.0.tgz",
|
||||
@@ -4768,6 +4791,18 @@
|
||||
"node": ">=16.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/filename-reserved-regex": {
|
||||
"version": "3.0.0",
|
||||
"resolved": "https://registry.npmjs.org/filename-reserved-regex/-/filename-reserved-regex-3.0.0.tgz",
|
||||
"integrity": "sha512-hn4cQfU6GOT/7cFHXBqeBg2TbrMBgdD0kcjLhvSQYYwm3s4B6cjvBfb7nBALJLAXqmU5xajSa7X2NnUud/VCdw==",
|
||||
"license": "MIT",
|
||||
"engines": {
|
||||
"node": "^12.20.0 || ^14.13.1 || >=16.0.0"
|
||||
},
|
||||
"funding": {
|
||||
"url": "https://github.com/sponsors/sindresorhus"
|
||||
}
|
||||
},
|
||||
"node_modules/fill-range": {
|
||||
"version": "7.1.1",
|
||||
"resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.1.1.tgz",
|
||||
@@ -9361,6 +9396,21 @@
|
||||
"dev": true,
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/valid-filename": {
|
||||
"version": "4.0.0",
|
||||
"resolved": "https://registry.npmjs.org/valid-filename/-/valid-filename-4.0.0.tgz",
|
||||
"integrity": "sha512-VEYTpTVPMgO799f2wI7zWf0x2C54bPX6NAfbZ2Z8kZn76p+3rEYCTYVYzMUcVSMvakxMQTriBf24s3+WeXJtEg==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"filename-reserved-regex": "^3.0.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": "^12.20.0 || ^14.13.1 || >=16.0.0"
|
||||
},
|
||||
"funding": {
|
||||
"url": "https://github.com/sponsors/sindresorhus"
|
||||
}
|
||||
},
|
||||
"node_modules/vfile": {
|
||||
"version": "6.0.3",
|
||||
"resolved": "https://registry.npmjs.org/vfile/-/vfile-6.0.3.tgz",
|
||||
|
@@ -19,6 +19,7 @@
|
||||
"@tailwindcss/vite": "^4.1.11",
|
||||
"astro": "^5.12.8",
|
||||
"astro-icon": "^1.1.5",
|
||||
"astro-robots-txt": "^1.0.0",
|
||||
"astro-seo-schema": "^5.1.0",
|
||||
"get-audio-duration": "^4.0.1",
|
||||
"schema-dts": "^1.1.5",
|
||||
@@ -26,6 +27,7 @@
|
||||
},
|
||||
"devDependencies": {
|
||||
"@cspell/dict-en-au": "^1.1.4",
|
||||
"@shikijs/transformers": "^3.9.2",
|
||||
"@types/howler": "^2.2.12",
|
||||
"@typescript-eslint/eslint-plugin": "^8.38.0",
|
||||
"@typescript-eslint/parser": "^8.38.0",
|
||||
|
11
src/components/MDX/A.astro
Normal file
11
src/components/MDX/A.astro
Normal file
@@ -0,0 +1,11 @@
|
||||
---
|
||||
import type { HTMLAttributes } from "astro/types";
|
||||
|
||||
interface Props extends HTMLAttributes<"a"> {}
|
||||
|
||||
import Link from "@components/Link.astro";
|
||||
|
||||
const { href, ...attrs } = Astro.props as Props;
|
||||
---
|
||||
|
||||
<Link href={href} {...attrs}><slot /></Link>
|
7
src/components/MDX/Blockquote.astro
Normal file
7
src/components/MDX/Blockquote.astro
Normal file
@@ -0,0 +1,7 @@
|
||||
<div class="flex w-full items-center">
|
||||
<blockquote
|
||||
class="border-primary mx-auto my-8 max-w-xl border-l-6 py-2 pl-4 italic"
|
||||
>
|
||||
<p class="text-lg font-light"><slot /></p>
|
||||
</blockquote>
|
||||
</div>
|
112
src/components/MDX/CodeSnippet.astro
Normal file
112
src/components/MDX/CodeSnippet.astro
Normal file
@@ -0,0 +1,112 @@
|
||||
---
|
||||
import { Icon } from "astro-icon/components";
|
||||
|
||||
const meta: Record<string, string> = {};
|
||||
const {
|
||||
"data-meta": dataMeta,
|
||||
"data-code": dataCode,
|
||||
class: className,
|
||||
...props
|
||||
} = Astro.props;
|
||||
|
||||
if (dataMeta) {
|
||||
dataMeta.split(",").forEach((prop: string) => {
|
||||
const tokens = prop.split("=");
|
||||
meta[tokens[0].trim()] = tokens[1];
|
||||
});
|
||||
}
|
||||
|
||||
const languageIcons: Record<string, string> = {
|
||||
javascript: "mdi:language-javascript"
|
||||
};
|
||||
|
||||
const languageIcon = languageIcons[props["data-language"]];
|
||||
|
||||
const title = meta.title;
|
||||
---
|
||||
|
||||
<figure class="my-4 rounded-b">
|
||||
{
|
||||
title && (
|
||||
<figcaption>
|
||||
<div class="bg-primary w-full rounded-t-md border-1 border-black px-4 py-2 text-white">
|
||||
<div class="flex justify-between">
|
||||
<div class="flex items-center justify-between gap-2 font-bold">
|
||||
{languageIcon && <Icon name={languageIcon} />}
|
||||
<p>{title}</p>
|
||||
</div>
|
||||
<button id="copy__code">Copy Code</button>
|
||||
</div>
|
||||
</div>
|
||||
</figcaption>
|
||||
)
|
||||
}
|
||||
|
||||
<pre
|
||||
class:list={[
|
||||
"py-2",
|
||||
"border-x border-b",
|
||||
"rounded-b",
|
||||
!title ? "rounded-t border-t" : "",
|
||||
className
|
||||
]}
|
||||
{...props}><slot /></pre>
|
||||
</figure>
|
||||
|
||||
<style is:global>
|
||||
.astro-code {
|
||||
overflow-x: auto;
|
||||
}
|
||||
|
||||
.astro-code code {
|
||||
/* Define a counter for each <code> inside .astro-code */
|
||||
counter-reset: step;
|
||||
/* Start from zero, increment the counter */
|
||||
counter-increment: step 0;
|
||||
|
||||
font-size: 14px;
|
||||
|
||||
width: fit-content;
|
||||
min-width: 100%;
|
||||
display: block;
|
||||
}
|
||||
|
||||
.astro-code code .line {
|
||||
display: inline-block;
|
||||
width: 100%;
|
||||
padding-right: 2rem;
|
||||
}
|
||||
|
||||
.astro-code code .line::before {
|
||||
content: counter(step);
|
||||
counter-increment: step;
|
||||
width: 2rem;
|
||||
margin-right: 1.25rem;
|
||||
display: inline-block;
|
||||
margin-left: auto;
|
||||
text-align: right;
|
||||
|
||||
/* Fix element position during horizontal scroll */
|
||||
position: sticky;
|
||||
left: 0;
|
||||
z-index: 1;
|
||||
|
||||
/* Give a bit of space to counter on horizontal scroll */
|
||||
padding-right: 0.25rem;
|
||||
|
||||
/* Illustrative purpose, please extract the value from the theme instead */
|
||||
background-color: white;
|
||||
color: hsla(0, 0%, 0%, 0.5);
|
||||
}
|
||||
</style>
|
||||
|
||||
<script define:vars={{ dataCode }}>
|
||||
if (typeof navigator.clipboard !== undefined) {
|
||||
const trigger = document.querySelector("#copy__code");
|
||||
|
||||
trigger.addEventListener("click", () => {
|
||||
// Write the code to clipboard
|
||||
navigator.clipboard.writeText(dataCode);
|
||||
});
|
||||
}
|
||||
</script>
|
1
src/components/MDX/H1.astro
Normal file
1
src/components/MDX/H1.astro
Normal file
@@ -0,0 +1 @@
|
||||
<h1 class="font-header text-3xl"><slot /></h1>
|
1
src/components/MDX/H2.astro
Normal file
1
src/components/MDX/H2.astro
Normal file
@@ -0,0 +1 @@
|
||||
<h2 class="font-header text-2xl"><slot /></h2>
|
1
src/components/MDX/H3.astro
Normal file
1
src/components/MDX/H3.astro
Normal file
@@ -0,0 +1 @@
|
||||
<h3 class="font-header text-xl"><slot /></h3>
|
1
src/components/MDX/H4.astro
Normal file
1
src/components/MDX/H4.astro
Normal file
@@ -0,0 +1 @@
|
||||
<h4 class="font-header text-lg"><slot /></h4>
|
1
src/components/MDX/H5.astro
Normal file
1
src/components/MDX/H5.astro
Normal file
@@ -0,0 +1 @@
|
||||
<h5 class="font-base text-base font-bold"><slot /></h5>
|
1
src/components/MDX/H6.astro
Normal file
1
src/components/MDX/H6.astro
Normal file
@@ -0,0 +1 @@
|
||||
<h6 class="font-base text-base underline"><slot /></h6>
|
10
src/components/MDX/P.astro
Normal file
10
src/components/MDX/P.astro
Normal file
@@ -0,0 +1,10 @@
|
||||
---
|
||||
import type { HTMLAttributes } from "astro/types";
|
||||
import Paragraph from "../Paragraph.astro";
|
||||
|
||||
interface Props extends HTMLAttributes<"p"> {}
|
||||
|
||||
const { ...attrs } = Astro.props as Props;
|
||||
---
|
||||
|
||||
<Paragraph className="my-4" {...attrs}><slot /></Paragraph>
|
@@ -1,6 +1,5 @@
|
||||
---
|
||||
import ImageCarousel from "@components/ImageCarousel.astro";
|
||||
import SectionTitle from "@components/SectionTitle.astro";
|
||||
import MainLayout from "@layouts/MainLayout.astro";
|
||||
|
||||
import { getCollection, render } from "astro:content";
|
||||
@@ -35,6 +34,17 @@ const seoImage: SiteImage = {
|
||||
width: hero.width,
|
||||
height: hero.height
|
||||
};
|
||||
|
||||
import A from "@components/MDX/A.astro";
|
||||
import Blockquote from "@components/MDX/Blockquote.astro";
|
||||
import CodeSnippet from "@components/MDX/CodeSnippet.astro";
|
||||
import H1 from "@components/MDX/H1.astro";
|
||||
import H2 from "@components/MDX/H2.astro";
|
||||
import H3 from "@components/MDX/H3.astro";
|
||||
import H4 from "@components/MDX/H4.astro";
|
||||
import H5 from "@components/MDX/H5.astro";
|
||||
import H6 from "@components/MDX/H6.astro";
|
||||
import P from "@components/MDX/P.astro";
|
||||
---
|
||||
|
||||
<MainLayout
|
||||
@@ -61,10 +71,21 @@ const seoImage: SiteImage = {
|
||||
</div>
|
||||
</section>
|
||||
<section id="projects" class="bg-white dark:bg-gray-950">
|
||||
<div <div class="mx-auto max-w-4xl px-8 py-16 text-center">
|
||||
<SectionTitle>{project.data.title}</SectionTitle>
|
||||
|
||||
<Content />
|
||||
<div <div class="mx-auto max-w-4xl px-8 py-16 text-justify md:text-left">
|
||||
<Content
|
||||
components={{
|
||||
p: P,
|
||||
a: A,
|
||||
h1: H1,
|
||||
h2: H2,
|
||||
h3: H3,
|
||||
h4: H4,
|
||||
h5: H5,
|
||||
h6: H6,
|
||||
blockquote: Blockquote,
|
||||
pre: CodeSnippet
|
||||
}}
|
||||
/>
|
||||
</div>
|
||||
</section>
|
||||
</div>
|
||||
|
@@ -1,4 +1,5 @@
|
||||
@import url("https://fonts.googleapis.com/css2?family=Roboto&display=swap");
|
||||
@import url("https://fonts.googleapis.com/css2?family=Fira+Code:wght@300..700&family=Roboto:ital,wght@0,100..900;1,100..900&display=swap");
|
||||
@import url("https://fonts.googleapis.com/css2?family=Fira+Code:wght@300..700&display=swap");
|
||||
@import "tailwindcss";
|
||||
@custom-variant dark (&:where([data-theme=dark], [data-theme=dark] *));
|
||||
|
||||
@@ -7,6 +8,7 @@
|
||||
--font-header: "Lutschine Bold", sans-serif;
|
||||
--font-header-alt: "Lutschine Regular", sans-serif;
|
||||
--font-body: "Roboto", sans-serif;
|
||||
--font-mono: "Fira Code", monospace;
|
||||
|
||||
--animate-floaty: floaty 18s forwards linear infinite;
|
||||
|
||||
|
Reference in New Issue
Block a user