diff --git a/.gitmodules b/.gitmodules index e95474d1..83a27611 100644 --- a/.gitmodules +++ b/.gitmodules @@ -1,3 +1,11 @@ -[submodule "code/libs/dcs-bios/dcs-bios-arduino-library"] +[submodule "dcs-bios-arduino-library"] path = code/libs/dcs-bios/dcs-bios-arduino-library url = git@github.com:dcs-bios/dcs-bios-arduino-library.git + +# Since I don't have an active subscription for FontAwesome Pro anymore +# I need to bundle them using my own private repository. This means you +# likely can't run this blog by yourself after cloning it, but that is +# not the point of this repostitory anyway. +[submodule "fontawesome-pro"] + path = blog/public/fontawesome-pro + url = git@github.com:padarom/fontawesome-pro.git diff --git a/blog/.gitignore b/blog/.gitignore index 557f97c6..6d4c0aa0 100644 --- a/blog/.gitignore +++ b/blog/.gitignore @@ -1,3 +1,21 @@ +# build output +dist/ + +# generated types +.astro/ + +# dependencies node_modules/ -.cache/ -public + +# logs +npm-debug.log* +yarn-debug.log* +yarn-error.log* +pnpm-debug.log* + +# environment variables +.env +.env.production + +# macOS-specific files +.DS_Store diff --git a/blog/.vscode/extensions.json b/blog/.vscode/extensions.json new file mode 100644 index 00000000..22a15055 --- /dev/null +++ b/blog/.vscode/extensions.json @@ -0,0 +1,4 @@ +{ + "recommendations": ["astro-build.astro-vscode"], + "unwantedRecommendations": [] +} diff --git a/blog/.vscode/launch.json b/blog/.vscode/launch.json new file mode 100644 index 00000000..d6422097 --- /dev/null +++ b/blog/.vscode/launch.json @@ -0,0 +1,11 @@ +{ + "version": "0.2.0", + "configurations": [ + { + "command": "./node_modules/.bin/astro dev", + "name": "Development server", + "request": "launch", + "type": "node-terminal" + } + ] +} diff --git a/blog/CNAME b/blog/CNAME deleted file mode 100644 index f946780b..00000000 --- a/blog/CNAME +++ /dev/null @@ -1 +0,0 @@ -hogpit.muehl.dev diff --git a/blog/README.md b/blog/README.md new file mode 100644 index 00000000..1db3fb39 --- /dev/null +++ b/blog/README.md @@ -0,0 +1,54 @@ +# Astro Starter Kit: Basics + +```sh +npm create astro@latest -- --template basics +``` + +[![Open in StackBlitz](https://developer.stackblitz.com/img/open_in_stackblitz.svg)](https://stackblitz.com/github/withastro/astro/tree/latest/examples/basics) +[![Open with CodeSandbox](https://assets.codesandbox.io/github/button-edit-lime.svg)](https://codesandbox.io/p/sandbox/github/withastro/astro/tree/latest/examples/basics) +[![Open in GitHub Codespaces](https://github.com/codespaces/badge.svg)](https://codespaces.new/withastro/astro?devcontainer_path=.devcontainer/basics/devcontainer.json) + +> πŸ§‘β€πŸš€ **Seasoned astronaut?** Delete this file. Have fun! + +![just-the-basics](https://github.com/withastro/astro/assets/2244813/a0a5533c-a856-4198-8470-2d67b1d7c554) + +## πŸš€ Project Structure + +Inside of your Astro project, you'll see the following folders and files: + +```text +/ +β”œβ”€β”€ public/ +β”‚ └── favicon.svg +β”œβ”€β”€ src/ +β”‚ β”œβ”€β”€ components/ +β”‚ β”‚ └── Card.astro +β”‚ β”œβ”€β”€ layouts/ +β”‚ β”‚ └── Layout.astro +β”‚ └── pages/ +β”‚ └── index.astro +└── package.json +``` + +Astro looks for `.astro` or `.md` files in the `src/pages/` directory. Each page is exposed as a route based on its file name. + +There's nothing special about `src/components/`, but that's where we like to put any Astro/React/Vue/Svelte/Preact components. + +Any static assets, like images, can be placed in the `public/` directory. + +## 🧞 Commands + +All commands are run from the root of the project, from a terminal: + +| Command | Action | +| :------------------------ | :----------------------------------------------- | +| `npm install` | Installs dependencies | +| `npm run dev` | Starts local dev server at `localhost:4321` | +| `npm run build` | Build your production site to `./dist/` | +| `npm run preview` | Preview your build locally, before deploying | +| `npm run astro ...` | Run CLI commands like `astro add`, `astro check` | +| `npm run astro -- --help` | Get help using the Astro CLI | + +## πŸ‘€ Want to learn more? + +Feel free to check [our documentation](https://docs.astro.build) or jump into our [Discord server](https://astro.build/chat). diff --git a/blog/astro.config.mjs b/blog/astro.config.mjs new file mode 100644 index 00000000..148cd3c8 --- /dev/null +++ b/blog/astro.config.mjs @@ -0,0 +1,15 @@ +import { defineConfig } from 'astro/config'; +import qwikdev from "@qwikdev/astro"; + +import tailwind from "@astrojs/tailwind"; +import mdx from '@astrojs/mdx' + +// https://astro.build/config +export default defineConfig({ + vite: { + resolve: { + preserveSymlinks: true + } + }, + integrations: [qwikdev(), tailwind(), mdx()] +}); diff --git a/blog/bun.lockb b/blog/bun.lockb new file mode 100755 index 00000000..49074a6d Binary files /dev/null and b/blog/bun.lockb differ diff --git a/blog/content/parts/misc/.gitkeep b/blog/content/parts/misc/.gitkeep deleted file mode 100644 index e69de29b..00000000 diff --git a/blog/content/parts/misc/prusa-mk3s/index.md b/blog/content/parts/misc/prusa-mk3s/index.md deleted file mode 100644 index 1d3cb700..00000000 --- a/blog/content/parts/misc/prusa-mk3s/index.md +++ /dev/null @@ -1,7 +0,0 @@ ---- -title: Prusa MK3S -released: 2023-09-07 -updated: 2023-09-07 ---- - -TBD. \ No newline at end of file diff --git a/blog/content/parts/panels/.gitkeep b/blog/content/parts/panels/.gitkeep deleted file mode 100644 index e69de29b..00000000 diff --git a/blog/content/parts/panels/elec-pwr/index.md b/blog/content/parts/panels/elec-pwr/index.md deleted file mode 100644 index f0b783da..00000000 --- a/blog/content/parts/panels/elec-pwr/index.md +++ /dev/null @@ -1,17 +0,0 @@ ---- -title: Electrical Power Panel -heroImage: ./first_iteration.jpg -heroSubtitle: The first proper iteration of my Electrical Power Panel. This was constructed and milled on my CNC machine. It doesn't yet include its green backlight in this picture. -released: 2021-07-02 -updated: 2023-09-07 ---- - -The first thing I ever tried to construct for my simulator was an HSI. I knew early on that I didn't just want to have all my instruments be LCD screens, I wanted real mechanical ones. - -Therefore I started constructing my own and bought my first 3D printer for it. - -At some point the instrument started seeming really daunting and getting more complex than I envisioned it originally. I wanted to know how an actual HSI is constructed, but couldn't find any pictures of its mechanics. - -I kept looking around for old HSIs on ebay until I eventually found one that seemed to match what I was constructing. An **AF/A24J-1**, the HSI of an F-4 Phantom, which I quickly bought for just shy of 200€. - -My plan wasn't to use this instrument, I still wanted to build my own, but wanted to reverse engineer the original to get some inspiration from it. diff --git a/blog/gatsby-browser.js b/blog/gatsby-browser.js deleted file mode 100644 index 6fc84837..00000000 --- a/blog/gatsby-browser.js +++ /dev/null @@ -1,2 +0,0 @@ -import './src/styles/global.css' -import './src/styles/base.css' diff --git a/blog/gatsby-config.js b/blog/gatsby-config.js deleted file mode 100644 index 2cbcf07d..00000000 --- a/blog/gatsby-config.js +++ /dev/null @@ -1,82 +0,0 @@ -module.exports = { - siteMetadata: { - title: 'Hogpit', - }, - trailingSlash: 'never', - plugins: [ - 'gatsby-plugin-image', - 'gatsby-plugin-react-helmet', - // 'gatsby-plugin-sitemap', - { - resolve: 'gatsby-plugin-manifest', - options: { - icon: 'src/images/icon.png', - }, - }, - { - resolve: 'gatsby-plugin-google-fonts', - options: { - fonts: [ - 'righteous:400', - 'roboto:300,400,500,600', - 'merriweather', - 'Roboto Mono', - ], - display: 'swap' - } - }, - { - resolve: 'gatsby-plugin-disqus', - options: { - shortname: 'hogpit', - }, - }, - 'gatsby-plugin-postcss', - 'gatsby-plugin-emotion', - { - resolve: 'gatsby-plugin-mdx', - options: { - extensions: ['.mdx', '.md'], - }, - }, - 'gatsby-plugin-sharp', - 'gatsby-transformer-sharp', - 'gatsby-transformer-yaml', - { - resolve: 'gatsby-source-filesystem', - options: { - name: 'parts', - path: './content/parts/', - fastHash: true, - }, - __key: 'parts', - }, - { - resolve: 'gatsby-source-filesystem', - options: { - name: 'images', - path: './content/images/', - fastHash: true, - }, - __key: 'images', - }, - { - resolve: 'gatsby-source-filesystem', - options: { - name: 'posts', - path: './content/posts/', - fastHash: true, - }, - __key: 'posts', - }, - { - resolve: 'gatsby-source-filesystem', - options: { - name: 'authors', - path: './content/authors/', - fastHash: true, - }, - __key: 'authors', - }, - ], -}; diff --git a/blog/gatsby-node.js b/blog/gatsby-node.js deleted file mode 100644 index 440ad92e..00000000 --- a/blog/gatsby-node.js +++ /dev/null @@ -1,76 +0,0 @@ -const path = require('path') -const readingTime = require('reading-time') - -const postTemplate = path.resolve('./src/templates/BlogPost.js') -const collectionTemplate = path.resolve('./src/templates/CollectionList.js') - -exports.createPages = async ({ graphql, actions }) => { - const { createPage } = actions - - // Create pages from MDX files - const { data } = await graphql(` - { - allMdx(filter: {internal: {contentFilePath: {regex: "/index.mdx?$/"}}}) { - nodes { - id - internal { contentFilePath } - parent { - ... on File { - relativeDirectory - } - } - } - } - } - `) - - data.allMdx.nodes.forEach(node => { - createPage({ - path: node.parent.relativeDirectory, - component: `${postTemplate}?__contentFilePath=${node.internal.contentFilePath}`, - context: { id: node.id }, - }) - }) - - await Promise.all(['parts', 'posts'].map(async (collection) => { - const { data } = await graphql(` - query($collection: String!) { - posts: allFile( - filter: {sourceInstanceName: {eq: $collection}, name: {eq: "index"}, extension: {in: ["md", "mdx"]}} - ) { - totalCount - } - } - `, { collection }) - - const POSTS_PER_PAGE = 9 - const numPages = Math.ceil(data.posts.totalCount / POSTS_PER_PAGE) - - Array.from({ length: numPages }).forEach((_, i) => { - createPage({ - path: `/${collection}/${i + 1}`, - component: collectionTemplate, - context: { - collection, - currentPage: i + 1, - numPages, - limit: POSTS_PER_PAGE, - skip: i * POSTS_PER_PAGE, - }, - }) - }) - })) -} - -exports.onCreateNode = ({ node, getNode, actions }) => { - const { createNodeField } = actions - - // Add reading time to MDX nodes - if (node.internal.type === 'Mdx') { - createNodeField({ - node, - name: 'timeToRead', - value: readingTime(node.body) - }) - } -} diff --git a/blog/gatsby-ssr.js b/blog/gatsby-ssr.js deleted file mode 100644 index 3355a8b9..00000000 --- a/blog/gatsby-ssr.js +++ /dev/null @@ -1,10 +0,0 @@ -import React from 'react' - -export const onRenderBody = ({ setHeadComponents }) => { - setHeadComponents([ - diff --git a/blog/src/components/Header.js b/blog/src/components/Header.js deleted file mode 100644 index c5009fc1..00000000 --- a/blog/src/components/Header.js +++ /dev/null @@ -1,57 +0,0 @@ -import React, { useState } from 'react' -import Icon from './Icon' -import tw from 'twin.macro' -import Helmet from 'react-helmet' -import { Link } from 'gatsby' - -const Container = tw.div` - pt-16 pb-24 flex justify-between items-center -` - -const LinkedLogo = tw(Link)` - font-page-title text-4xl p-2 -m-2 -` - -const Menu = tw.div` - px-3 ml-auto mr-10 -` - -const IconContainer = tw.div` - text-2xl text-gray-500 dark:text-gray-300 -` - -const MenuLink = tw(Link)` - px-3 hover:text-gray-700 dark:hover:text-gray-300 -` - -export default function Header () { - const [darkMode, setDarkMode] = useState(false) - - return ( - - - - - - - Hog - pit - - - - About - Simulator - Parts - Blog - - - - setDarkMode(!darkMode) } - /> - - - ) -} diff --git a/blog/src/components/Header.tsx b/blog/src/components/Header.tsx new file mode 100644 index 00000000..485e9955 --- /dev/null +++ b/blog/src/components/Header.tsx @@ -0,0 +1,42 @@ +import { Slot, component$, useSignal, $ } from '@builder.io/qwik' +import { Icon } from './Icon' + +const MenuLink = component$((props: { href: string }) => + + + +) + +export const Header = component$(() => { + const darkMode = useSignal(false) + const toggleDarkMode = $(() => { + darkMode.value = !darkMode.value + document.documentElement.classList.toggle('dark') + }) + + return ( +
+ + Hog + pit + + +
+ About + Simulator + Parts + Blog +
+ +
+ +
+
+ ) +}) diff --git a/blog/src/components/Icon.js b/blog/src/components/Icon.js deleted file mode 100644 index 25ad5495..00000000 --- a/blog/src/components/Icon.js +++ /dev/null @@ -1,13 +0,0 @@ -import tw, { styled } from 'twin.macro' - -const Icon = styled.i(({ active }) => [ - tw` - text-gray-400 p-2 rounded-full cursor-pointer - bg-transparent hover:bg-gray-100 - dark:text-gray-400 dark:hover:bg-gray-700 - transition-colors duration-300 - `, - active && tw`text-gray-900 dark:text-gray-100`, -]) - -export default Icon diff --git a/blog/src/components/Icon.tsx b/blog/src/components/Icon.tsx new file mode 100644 index 00000000..9af77890 --- /dev/null +++ b/blog/src/components/Icon.tsx @@ -0,0 +1,16 @@ +import { component$ } from '@builder.io/qwik' +import type { ClassList } from '@builder.io/qwik' +// import './fontawesome-pro/js/fontawesome' + +type Props = { active: Boolean, class?: ClassList } + +export const Icon = component$((props: Props) => { + return +}) diff --git a/blog/src/components/IndexPage.tsx b/blog/src/components/IndexPage.tsx new file mode 100644 index 00000000..df2729d1 --- /dev/null +++ b/blog/src/components/IndexPage.tsx @@ -0,0 +1,64 @@ +import { component$, $, useSignal } from '@builder.io/qwik' +import { getCollection, CollectionEntry } from 'astro:content' +import { Icon } from '../components/Icon' +import { Author } from '../components/Author' +import { PostsList } from '../components/PostsList' + +const author = { + slug: 'chris', + avatar: 'https://avatars.githubusercontent.com/u/3678770?v=4', + bio: ` + Written by Christopher, a programmer and maker from the Frankfurt metropolitan + area in Germany who loves to build things. He's a fan of aviation and flight simulators + and is currently building an A-10C simulator cockpit. + `.trim(), +} + +let posts: CollectionEntry<'parts'>[] = await getCollection('parts') +posts = posts + .sort((a, b) => a.data.updated > b.data.updated ? -1 : 1) + .slice(0, 6) + .map(post => ({ data: post.data, body: post.body, slug: post.slug })) + +export const IndexPage = component$(() => { + const useTabularLayout = useSignal(false) + const setTabularLayout = $((value: boolean) => { + useTabularLayout.value = value + }) + + return ( +
+
+ Welcome to my Hogpit project, where I try to document my journey + of building an A‑10C simulator pit. +
+ +
+
+ +
+ + +
+ + +
+ ) +}) diff --git a/blog/src/components/Layout.js b/blog/src/components/Layout.js deleted file mode 100644 index 8e2daf44..00000000 --- a/blog/src/components/Layout.js +++ /dev/null @@ -1,23 +0,0 @@ -import React from 'react' -import Header from './Header' -import tw from 'twin.macro' -import { Global } from '@emotion/react' -import { GlobalStyles } from 'twin.macro' -import globalStyles from './styles' - -const Container = tw.div` - container mx-auto px-6 md:px-16 pb-28 -` - -export default function Layout ({ children }) { - return ( - - - - -
- - {children} - - ) -} diff --git a/blog/src/components/PostsList.tsx b/blog/src/components/PostsList.tsx new file mode 100644 index 00000000..77cd844a --- /dev/null +++ b/blog/src/components/PostsList.tsx @@ -0,0 +1,64 @@ +import { component$ } from '@builder.io/qwik' +import { type CollectionEntry } from 'astro:content' +import { createExcerpt } from '../utils/excerpt' +import { calculateReadTime } from '../utils/readtime' + +type PostProps = { + post: CollectionEntry<'parts'>, + tabular: boolean, + index: number +} + +const Post = component$(({ tabular, post, index }: PostProps) => { + const excerpt = createExcerpt(post.body || '', 280) + const readTime = calculateReadTime(post.body || '') + + return ( + +
+ {post.data.heroSubtitle} +
+ +
+

{post.data.title}

+

{excerpt}

+

+ {new Date(post.data.updated).toLocaleDateString()} · {readTime} min read +

+
+
+ ) +}) + +type Props = { + tabular: boolean, + posts: CollectionEntry<'parts'>[], +} + +export const PostsList = component$(({ tabular, posts }: Props) => { + const renderedPosts = posts.map((node, i) => ( + + )) + + return ( +
+ {renderedPosts} +
+ ) +}) diff --git a/blog/src/components/blog/FullPost.js b/blog/src/components/blog/FullPost.js deleted file mode 100644 index 8b76d7e6..00000000 --- a/blog/src/components/blog/FullPost.js +++ /dev/null @@ -1,50 +0,0 @@ -import * as React from 'react' -import { MDXProvider } from '@mdx-js/react' -import { CodeBlock, github } from 'react-code-blocks' -import { Disqus } from 'gatsby-plugin-disqus' -import tw from 'twin.macro' - -const InlineCode = tw.code` - text-gray-500 px-[2px] bg-gray-100 - dark:text-gray-400 dark:bg-gray-700 -` - -const components = { - p: tw.p` - mb-6 - `, - a: tw.a` - text-indigo-400 hover:underline - dark:text-indigo-300 - `, - code: ({ className, children }) => { - if (!className) return {children} - - const language = className.replace('language-', '') - - return - }, -} - -export default function FullPost ({ post, children }) { - const disqusConfig = { - identifier: post.parent.relativeDirectory, - title: post.frontmatter.title - } - - return ( - <> - - {children} - - -
- - - - ) -} diff --git a/blog/src/components/blog/PartsPostList.js b/blog/src/components/blog/PartsPostList.js deleted file mode 100644 index 9cd9692b..00000000 --- a/blog/src/components/blog/PartsPostList.js +++ /dev/null @@ -1,24 +0,0 @@ -import React from 'react' -import PostList from './PostList' -import { useStaticQuery, graphql } from 'gatsby' - -export default function PartsPostList ({ tabularLayout }) { - const { posts } = useStaticQuery(graphql` - query PostQuery { - posts: allFile( - filter: { - sourceInstanceName: {eq: "parts"}, - relativeDirectory: {regex: "/^(instruments|panels|frames)/"} - name: {eq: "index"}, - extension: {in: ["md", "mdx"]} - } - sort: {childMdx: {frontmatter: {updated: DESC}}} - limit: 9 - ) { - ...PostListQuery - } - } - `) - - return -} diff --git a/blog/src/components/blog/PostList.js b/blog/src/components/blog/PostList.js deleted file mode 100644 index 8e2530b0..00000000 --- a/blog/src/components/blog/PostList.js +++ /dev/null @@ -1,60 +0,0 @@ -import React from 'react' -import tw from 'twin.macro' -import { Link, useStaticQuery, graphql } from 'gatsby' -import { GatsbyImage, getImage } from 'gatsby-plugin-image' - -const Container = tw.div` - grid grid-cols-1 gap-12 pb-12 -` - -const styles = { - title: tw`font-serif text-2xl font-bold mb-3`, - excerpt: tw`mb-3`, - subtext: tw`text-gray-400 font-bold text-sm`, - container: ({ tabularLayout }) => [ - tabularLayout && tw`grid grid-cols-3 gap-x-10 gap-y-20`, - ], - post: ({ tabularLayout }) => [ - tabularLayout && tw`grid grid-cols-1`, - !tabularLayout && tw`grid grid-cols-2 gap-20`, - ], - description: ({ index, tabularLayout }) => [ - tabularLayout && (index % 2 ? tw`pb-7 pt-4 border-gray-100 border-t -order-1` : tw`pt-7 pb-2 border-gray-100 border-b`), - !tabularLayout && tw`py-10`, - ], -} - -export default function PostList ({ posts, tabularLayout }) { - const blogPosts = posts.map((node, i) => ( - - )) - - return ( - - {blogPosts} - - ) -} - -function BlogPost ({ node, index, tabularLayout }) { - const date = node.content.frontmatter.updated - - return ( - -
- -
- -
-

{node.content.frontmatter.title}

-
{node.content.excerpt}
-
- {node.content.frontmatter.updated} · {node.content.fields.timeToRead.minutes} min read -
-
- - ) -} diff --git a/blog/src/components/blog/lists/index.js b/blog/src/components/blog/lists/index.js deleted file mode 100644 index b9bd199b..00000000 --- a/blog/src/components/blog/lists/index.js +++ /dev/null @@ -1,32 +0,0 @@ -import { graphql } from 'gatsby' - -export const query = graphql` - fragment PostListQuery on FileConnection { - totalCount - nodes { - id - relativeDirectory - changeTime(formatString: "MMMM Do, YYYY") - content: childMdx { - excerpt - fields { - timeToRead { minutes } - } - frontmatter { - title - updated(formatString: "MMMM Do, YYYY") - released(formatString: "MMMM Do, YYYY") - heroImage { - childImageSharp { - gatsbyImageData( - width: 500, - placeholder: BLURRED, - formats: [AUTO, WEBP, JPG] - ) - } - } - } - } - } - } -` diff --git a/blog/src/components/mdx/Link.astro b/blog/src/components/mdx/Link.astro new file mode 100644 index 00000000..00bcf76a --- /dev/null +++ b/blog/src/components/mdx/Link.astro @@ -0,0 +1,8 @@ +--- +const { children } = Astro.props +const html = await Astro.slots.render('default') +--- + + + + diff --git a/blog/src/components/mdx/Paragraph.astro b/blog/src/components/mdx/Paragraph.astro new file mode 100644 index 00000000..0f014dff --- /dev/null +++ b/blog/src/components/mdx/Paragraph.astro @@ -0,0 +1,8 @@ +--- +const { children } = Astro.props +const html = await Astro.slots.render('default') +--- + +

+ +

diff --git a/blog/src/components/mdx/index.tsx b/blog/src/components/mdx/index.tsx new file mode 100644 index 00000000..fe9ac899 --- /dev/null +++ b/blog/src/components/mdx/index.tsx @@ -0,0 +1,7 @@ +import Link from './Link.astro' +import Paragraph from './Paragraph.astro' + +export const mdxComponents = { + p: Paragraph, + a: Link, +} diff --git a/blog/src/components/simulator/SceneComponent.js b/blog/src/components/simulator/SceneComponent.js deleted file mode 100644 index ca54c9c7..00000000 --- a/blog/src/components/simulator/SceneComponent.js +++ /dev/null @@ -1,41 +0,0 @@ -import React, { useEffect, useRef } from 'react' -import { Engine, Scene } from '@babylonjs/core' - -export default function SceneComponent ({ - antialias, engineOptions, adaptToDeviceRatio, sceneOptions, - onRender, onSceneReady, ...rest -}) { - const reactCanvas = useRef(null) - - useEffect(() => { - const { current: canvas } = reactCanvas - - if (!canvas) return - - canvas.innerWidth = window.innerWidth - - const engine = new Engine(canvas, antialias, engineOptions, adaptToDeviceRatio) - const scene = new Scene(engine, sceneOptions) - if (scene.isReady()) { - onSceneReady(scene) - } else { - scene.onReadyObservable.addOnce((scene) => onSceneReady(scene)) - } - - engine.runRenderLoop(() => { - if (typeof onRender === 'function') onRender(scene) - scene.render() - }) - - const resize = () => scene.getEngine().resize() - if (window) window.addEventListener('resize', resize) - - return () => { - scene.getEngine().dispose() - - if (window) window.removeEventListener('resize', resize) - } - }, [antialias, engineOptions, adaptToDeviceRatio, sceneOptions, onRender, onSceneReady]) - - return -} \ No newline at end of file diff --git a/blog/src/components/styles.js b/blog/src/components/styles.js deleted file mode 100644 index 027b44af..00000000 --- a/blog/src/components/styles.js +++ /dev/null @@ -1,13 +0,0 @@ -import tw, { css } from "twin.macro" - -const globalStyles = css` - body { - ${tw` - text-gray-900 - dark:bg-gray-800 dark:text-gray-100 - transition-all duration-200 - `} - } -` - -export default globalStyles diff --git a/blog/content/authors/authors.yml b/blog/src/content/authors/authors.yml similarity index 100% rename from blog/content/authors/authors.yml rename to blog/src/content/authors/authors.yml diff --git a/blog/src/content/config.ts b/blog/src/content/config.ts new file mode 100644 index 00000000..9096aa4d --- /dev/null +++ b/blog/src/content/config.ts @@ -0,0 +1,20 @@ +import { z, defineCollection } from 'astro:content' + +const posts = defineCollection({ + type: 'content', + schema: z.object({}), +}) + +const parts = defineCollection({ + type: 'content', + schema: ({ image }) => + z.object({ + title: z.string(), + heroImage: image(), + heroSubtitle: z.string(), + released: z.date(), + updated: z.date(), + }), +}) + +export const collections = { posts, parts } diff --git a/blog/content/images/.gitkeep b/blog/src/content/images/.gitkeep similarity index 100% rename from blog/content/images/.gitkeep rename to blog/src/content/images/.gitkeep diff --git a/blog/content/parts/frames/.gitkeep b/blog/src/content/parts/frames/.gitkeep similarity index 100% rename from blog/content/parts/frames/.gitkeep rename to blog/src/content/parts/frames/.gitkeep diff --git a/blog/content/parts/images/unsplash.jpg b/blog/src/content/parts/images/unsplash.jpg similarity index 100% rename from blog/content/parts/images/unsplash.jpg rename to blog/src/content/parts/images/unsplash.jpg diff --git a/blog/content/parts/instruments/adi/index.md b/blog/src/content/parts/instruments/adi/index.mdx similarity index 100% rename from blog/content/parts/instruments/adi/index.md rename to blog/src/content/parts/instruments/adi/index.mdx diff --git a/blog/content/parts/instruments/adi/side_picture.jpg b/blog/src/content/parts/instruments/adi/side_picture.jpg similarity index 100% rename from blog/content/parts/instruments/adi/side_picture.jpg rename to blog/src/content/parts/instruments/adi/side_picture.jpg diff --git a/blog/content/parts/instruments/hsi/index.md b/blog/src/content/parts/instruments/hsi/index.mdx similarity index 100% rename from blog/content/parts/instruments/hsi/index.md rename to blog/src/content/parts/instruments/hsi/index.mdx diff --git a/blog/content/parts/instruments/hsi/side_picture.jpg b/blog/src/content/parts/instruments/hsi/side_picture.jpg similarity index 100% rename from blog/content/parts/instruments/hsi/side_picture.jpg rename to blog/src/content/parts/instruments/hsi/side_picture.jpg diff --git a/blog/content/parts/panels/elec-pwr/first_iteration.jpg b/blog/src/content/parts/misc/mpcnc/first_iteration.jpg similarity index 100% rename from blog/content/parts/panels/elec-pwr/first_iteration.jpg rename to blog/src/content/parts/misc/mpcnc/first_iteration.jpg diff --git a/blog/content/parts/misc/mpcnc/index.md b/blog/src/content/parts/misc/mpcnc/index.mdx similarity index 53% rename from blog/content/parts/misc/mpcnc/index.md rename to blog/src/content/parts/misc/mpcnc/index.mdx index 628b8359..ded06873 100644 --- a/blog/content/parts/misc/mpcnc/index.md +++ b/blog/src/content/parts/misc/mpcnc/index.mdx @@ -2,6 +2,8 @@ title: MPCNC released: 2023-09-07 updated: 2023-09-07 +heroImage: ./first_iteration.jpg +heroSubtitle: Placeholder --- TBD. diff --git a/blog/src/content/parts/misc/photon-mono/first_iteration.jpg b/blog/src/content/parts/misc/photon-mono/first_iteration.jpg new file mode 100644 index 00000000..7a91415a Binary files /dev/null and b/blog/src/content/parts/misc/photon-mono/first_iteration.jpg differ diff --git a/blog/content/parts/misc/photon-mono/index.md b/blog/src/content/parts/misc/photon-mono/index.mdx similarity index 58% rename from blog/content/parts/misc/photon-mono/index.md rename to blog/src/content/parts/misc/photon-mono/index.mdx index a4773ceb..056f93bb 100644 --- a/blog/content/parts/misc/photon-mono/index.md +++ b/blog/src/content/parts/misc/photon-mono/index.mdx @@ -2,6 +2,8 @@ title: ANYCUBIC Photon Mono released: 2023-09-07 updated: 2023-09-07 +heroImage: ./first_iteration.jpg +heroSubtitle: Placeholder --- TBD. \ No newline at end of file diff --git a/blog/src/content/parts/misc/prusa-mk3s/first_iteration.jpg b/blog/src/content/parts/misc/prusa-mk3s/first_iteration.jpg new file mode 100644 index 00000000..7a91415a Binary files /dev/null and b/blog/src/content/parts/misc/prusa-mk3s/first_iteration.jpg differ diff --git a/blog/src/content/parts/misc/prusa-mk3s/index.mdx b/blog/src/content/parts/misc/prusa-mk3s/index.mdx new file mode 100644 index 00000000..077efdfe --- /dev/null +++ b/blog/src/content/parts/misc/prusa-mk3s/index.mdx @@ -0,0 +1,13 @@ +--- +title: Prusa MK3S +released: 2023-09-07 +updated: 2023-09-07 +heroImage: ./first_iteration.jpg +heroSubtitle: Placeholder +--- + +When I first decided to dive into building my A-10C Warthog simulator, I knew I’d need a reliable 3D printer to bring my ideas to life. After some research, I settled on the Prusa MK3S, which I bought as a kit and assembled myself. + +The assembly process was a learning experience, and it felt great to put together a tool that I knew would be crucial for my project. My main goal at the time was to design and print the Horizontal Situation Indicator, so my first prints were test pieces for that. While I haven’t printed as many parts for the simulator as I initially hoped, the Prusa MK3S has served me well. + +Since then, I’ve added a Bambulab P1S to my arsenal, but the Prusa MK3S will always be the printer that got me started on this journey. \ No newline at end of file diff --git a/blog/src/content/parts/panels/elec-pwr/first_iteration.jpg b/blog/src/content/parts/panels/elec-pwr/first_iteration.jpg new file mode 100644 index 00000000..7a91415a Binary files /dev/null and b/blog/src/content/parts/panels/elec-pwr/first_iteration.jpg differ diff --git a/blog/src/content/parts/panels/elec-pwr/index.mdx b/blog/src/content/parts/panels/elec-pwr/index.mdx new file mode 100644 index 00000000..0f674d3b --- /dev/null +++ b/blog/src/content/parts/panels/elec-pwr/index.mdx @@ -0,0 +1,35 @@ +--- +title: Electrical Power Panel +heroImage: ./first_iteration.jpg +heroSubtitle: The first proper iteration of my Electrical Power Panel. This was constructed and milled on my CNC machine. It doesn't yet include its green backlight in this picture. +released: 2021-07-02 +updated: 2024-08-30 +--- + +When I started planning my A-10C Warthog simulator, I knew the panels would be a major focus. They needed to be modular, each with a single connector to attach seamlessly to the cockpit bus. To kick things off and refine my design and production process, I chose to start with the Electrical Power Panel. + +This panel was a relatively straightforward choice, featuring only switchesβ€”both momentary and lockingβ€”making it an ideal first project to work out all the kinks in the build process. Here's how I approached it: + +### Layered Construction + +The panel is built using a three-layer approach: + +- **Backing Plate**: This layer holds the components and serves as the foundation. +- **Intermediate Plate**: A spacer that creates the necessary depth and space for the switches and wiring. +- **Front Plate**: The visible layer, painted and etched with backlit text, which gives the panel its finished look. + +All these layers are made from semi-transparent acrylic sheets that I machined on my DIY CNC (specifically, the MPCNC). Once all the feeds and speeds were dialed in for the acrylic and the router bits I was using everything came together nicely. + +### Assembly Process + +Once the layers were machined, I assembled the front two plates using ACRIFIX 1S 0116, an acrylic adhesive that melts the material and effectively welds the pieces together without leaving any residue. This glue is crucial for a clean finish. + +Next, I spray-painted the front two layers black, and then etched the text into the front plate using a V-bit. The result is sharp, backlit lettering that stands out just like the real thing. + +Finally, I attached the components to the back plate, soldered and connected everything, and secured the back plate to the front with screws. + +### Conclusion + +This first panel was a significant milestone in my simulator build. It allowed me to hone the techniques and processes that I’ll be using for the rest of the project. For those interested in a detailed breakdown of the assembly process, you can find more information [here]. + +This initial success has set a solid foundation for the rest of the build, and I’m excited to continue bringing each part of the A-10C cockpit to life. \ No newline at end of file diff --git a/blog/content/posts/2023-09-07-start-of-a-journey/index.md b/blog/src/content/posts/2023-09-07-start-of-a-journey/index.md similarity index 100% rename from blog/content/posts/2023-09-07-start-of-a-journey/index.md rename to blog/src/content/posts/2023-09-07-start-of-a-journey/index.md diff --git a/blog/src/env.d.ts b/blog/src/env.d.ts new file mode 100644 index 00000000..acef35f1 --- /dev/null +++ b/blog/src/env.d.ts @@ -0,0 +1,2 @@ +/// +/// diff --git a/blog/src/images/icon.png b/blog/src/images/icon.png deleted file mode 100644 index 38b2fb0e..00000000 Binary files a/blog/src/images/icon.png and /dev/null differ diff --git a/blog/src/layouts/Layout.astro b/blog/src/layouts/Layout.astro new file mode 100644 index 00000000..537a7029 --- /dev/null +++ b/blog/src/layouts/Layout.astro @@ -0,0 +1,36 @@ +--- +import { Header } from '../components/Header' +import '@fontsource/righteous' +import '@fontsource/roboto' +import '@fontsource/merriweather' + +interface Props { + title: string; +} + +const { title } = Astro.props; +--- + + + + + + + + + + {title} + + + + +
+
+ + +
+ + diff --git a/blog/src/layouts/MarkdownPostLayout.astro b/blog/src/layouts/MarkdownPostLayout.astro new file mode 100644 index 00000000..537a7029 --- /dev/null +++ b/blog/src/layouts/MarkdownPostLayout.astro @@ -0,0 +1,36 @@ +--- +import { Header } from '../components/Header' +import '@fontsource/righteous' +import '@fontsource/roboto' +import '@fontsource/merriweather' + +interface Props { + title: string; +} + +const { title } = Astro.props; +--- + + + + + + + + + + {title} + + + + +
+
+ + +
+ + diff --git a/blog/src/pages/404.js b/blog/src/pages/404.js deleted file mode 100644 index 053ae0e8..00000000 --- a/blog/src/pages/404.js +++ /dev/null @@ -1,54 +0,0 @@ -import * as React from "react" -import { Link } from "gatsby" - -// styles -const pageStyles = { - color: "#232129", - padding: "96px", - fontFamily: "-apple-system, Roboto, sans-serif, serif", -} -const headingStyles = { - marginTop: 0, - marginBottom: 64, - maxWidth: 320, -} - -const paragraphStyles = { - marginBottom: 48, -} -const codeStyles = { - color: "#8A6534", - padding: 4, - backgroundColor: "#FFF4DB", - fontSize: "1.25rem", - borderRadius: 4, -} - -// markup -const NotFoundPage = () => { - return ( -
- Not found -

Page not found

-

- Sorry{" "} - - πŸ˜” - {" "} - we couldn’t find what you were looking for. -
- {process.env.NODE_ENV === "development" ? ( - <> -
- Try creating a page in src/pages/. -
- - ) : null} -
- Go home. -

-
- ) -} - -export default NotFoundPage diff --git a/blog/src/pages/about.js b/blog/src/pages/about.js deleted file mode 100644 index 26c7d63e..00000000 --- a/blog/src/pages/about.js +++ /dev/null @@ -1,12 +0,0 @@ -import * as React from 'react' -import Layout from '../components/Layout' - -const AboutPage = ({ data }) => { - return ( - - Coming soon. - - ) -} - -export default AboutPage diff --git a/blog/src/pages/index.astro b/blog/src/pages/index.astro new file mode 100644 index 00000000..79c887a5 --- /dev/null +++ b/blog/src/pages/index.astro @@ -0,0 +1,8 @@ +--- +import Layout from '../layouts/Layout.astro' +import { IndexPage } from '../components/IndexPage' +--- + + + + diff --git a/blog/src/pages/index.js b/blog/src/pages/index.js deleted file mode 100644 index 1d648f30..00000000 --- a/blog/src/pages/index.js +++ /dev/null @@ -1,68 +0,0 @@ -import * as React from 'react' -import Layout from '../components/Layout' -import Author from '../components/Author' -import Icon from '../components/Icon' -import PartsPostList from '../components/blog/PartsPostList' -import tw from 'twin.macro' -import { graphql } from 'gatsby' - -const Header = tw.div` - mt-0 mb-8 md:(mt-4 mb-24) -` - -const Introduction = tw.div` - font-sans font-medium max-w-2xl leading-tight mb-20 - w-full text-3xl md:(w-3/4 text-4xl) -` - -const IndexPage = ({ data }) => { - const [useTabularLayout, setTabularLayout] = React.useState(false) - - return ( - -
- - Welcome to my Hogpit project, where I try to document my journey - of building an A‑10C simulator pit. - - - -
-
- -
- -
- setTabularLayout(true) } - /> - - setTabularLayout(false) } - /> -
-
-
- - -
- ) -} - -export const query = graphql`{ - author: authorsYaml(featured: {eq: true}) { - avatar - bio - slug - } -}` - -export default IndexPage diff --git a/blog/src/pages/parts/[type]/[slug].astro b/blog/src/pages/parts/[type]/[slug].astro new file mode 100644 index 00000000..d4facc3d --- /dev/null +++ b/blog/src/pages/parts/[type]/[slug].astro @@ -0,0 +1,47 @@ +--- +import { getCollection } from 'astro:content' +import { mdxComponents } from '../../../components/mdx' +import Disqus from '../../../components/Disqus.astro' +import MarkdownPostLayout from '../../../layouts/MarkdownPostLayout.astro' + +export async function getStaticPaths() { + const entries = await getCollection('parts') + return entries.map(entry => { + return { + params: { + slug: entry.slug.split('/').slice(1).join('/'), + type: entry.slug.split('/', 1)[0] + }, + props: { entry } + } + }) +} + +const { entry } = Astro.props +const { Content } = await entry.render() +--- + + +
+

{entry.data.title}

+ +
+ {entry.data.heroSubtitle} +

{entry.data.heroSubtitle}

+
+ +
+ +
+
+ +
+ +
+ +
+
diff --git a/blog/src/pages/simulator.js b/blog/src/pages/simulator.js deleted file mode 100644 index 5d974bab..00000000 --- a/blog/src/pages/simulator.js +++ /dev/null @@ -1,59 +0,0 @@ -import React from 'react' -import tw from 'twin.macro' -import colors from 'tailwindcss/colors' -import Layout from '../components/Layout' -import SceneComponent from '../components/simulator/SceneComponent' -import { Color3, FreeCamera, HemisphericLight, MeshBuilder, Vector3 } from '@babylonjs/core' - -let box -let darkMode = false - -const onSceneReady = (scene) => { - const camera = new FreeCamera('camera1', new Vector3(0, 5, -10), scene) - camera.setTarget(Vector3.Zero()) - - const canvas = scene.getEngine().getRenderingCanvas() - camera.attachControl(canvas, true) - - const light = new HemisphericLight('light', new Vector3(0, 1, 0), scene) - light.intensity = 0.7 - - box = MeshBuilder.CreateBox('box', { size: 2 }, scene) - box.position.y = 1 - - MeshBuilder.CreateGround('ground', { width: 6, height: 6 }, scene) -} - -const onRender = (scene) => { - scene.clearColor = Color3.FromHexString(darkMode ? colors.gray[800] : '#ffffff') - - if (box !== undefined) { - const deltaTimeInMillis = scene.getEngine().getDeltaTime() - - const rpm = 4 - box.rotation.y += (rpm / 60) * Math.PI * 2 * (deltaTimeInMillis / 1000) - } -} - -const Container = tw.div`w-full` - -export default function SimulatorPage() { - if (typeof MutationObserver !== 'undefined') { - const observer = new MutationObserver(() => { - darkMode = document.documentElement.classList.contains('dark') - }) - - observer.observe(document.documentElement, { - attributes: true, - attributeFilter: ['class'], - }) - } - - return ( - - - - - - ) -} diff --git a/blog/src/styles/base.css b/blog/src/styles/base.css deleted file mode 100644 index 464d6510..00000000 --- a/blog/src/styles/base.css +++ /dev/null @@ -1,3 +0,0 @@ -body { - font-family: 'Merriweather'; -} diff --git a/blog/src/styles/global.css b/blog/src/styles/global.css deleted file mode 100644 index bd6213e1..00000000 --- a/blog/src/styles/global.css +++ /dev/null @@ -1,3 +0,0 @@ -@tailwind base; -@tailwind components; -@tailwind utilities; \ No newline at end of file diff --git a/blog/src/templates/BlogPost.js b/blog/src/templates/BlogPost.js deleted file mode 100644 index 8e865a39..00000000 --- a/blog/src/templates/BlogPost.js +++ /dev/null @@ -1,68 +0,0 @@ -import React from 'react' -import Layout from '../components/Layout' -import { GatsbyImage, getImage } from 'gatsby-plugin-image' -import { graphql } from 'gatsby' -import FullPost from '../components/blog/FullPost' -import tw from 'twin.macro' - -const Title = tw.h1` - text-5xl mx-auto font-serif font-bold max-w-2xl mb-16 -` - -const Content = tw.div` - mx-auto max-w-2xl text-lg -` - -const PageWrapper = tw.div`px-10` -const ImageWrapper = tw.div`mb-16` -const Subtitle = tw.p`mt-2 text-gray-500 text-sm` - -// TODO: tw props do not work in this file. I assume it is because the file -// is loaded using the gatsby-mdx loader and does therefore not get parsed -// by twin.macro. I have not found a solution to this yet. - -const Post = ({ data: { post }, children }) => { - return ( - - - {post.frontmatter.title} - - - - {post.frontmatter.heroSubtitle} - - - - - - - - ) -} - -export const pageQuery = graphql` - query($id: String!) { - post: mdx(id: { eq: $id }) { - parent { - ... on File { - relativeDirectory - } - } - frontmatter { - title - heroSubtitle - heroImage { - childImageSharp { - gatsbyImageData( - width: 1920, - placeholder: BLURRED, - formats: [AUTO, WEBP, JPG] - ) - } - } - } - } - } -` - -export default Post diff --git a/blog/src/templates/CollectionList.js b/blog/src/templates/CollectionList.js deleted file mode 100644 index a26442c7..00000000 --- a/blog/src/templates/CollectionList.js +++ /dev/null @@ -1,40 +0,0 @@ -import React from 'react' -import Layout from '../components/Layout' -import { graphql } from 'gatsby' -import PostList from '../components/blog/PostList' -import tw from 'twin.macro' - -const Title = tw.h1`text-5xl font-sans` -const Subtitle = tw.h1`text-xl mb-10 text-slate-400 font-sans` - -const Titles = { - posts: { title: 'Posts', subtitle: 'All blog posts I have written' }, - parts: { title: 'Parts', subtitle: 'Part descriptions' }, -} - -const CollectionList = ({ data: { posts }, pageContext }) => { - - return ( - - {Titles[pageContext.collection].title} - {Titles[pageContext.collection].subtitle} - - - - ) -} - -export const pageQuery = graphql` - query($collection: String!, $limit: Int!, $skip: Int!) { - posts: allFile( - limit: $limit, - skip: $skip, - filter: {sourceInstanceName: {eq: $collection}, name: {eq: "index"}, extension: {in: ["md", "mdx"]}} - sort: {childMdx: {frontmatter: {updated: DESC}}} - ) { - ...PostListQuery - } - } -` - -export default CollectionList diff --git a/blog/src/utils/excerpt.ts b/blog/src/utils/excerpt.ts new file mode 100644 index 00000000..796363f0 --- /dev/null +++ b/blog/src/utils/excerpt.ts @@ -0,0 +1,23 @@ +import MarkdownIt from 'markdown-it' +const parser = new MarkdownIt() + +export const createExcerpt = (body: string, length: number = 170) => { + const excerpt = parser + .render(body) + .split('\n') + .slice(0, 6) + .map((str: string) => str.replace(/<\/?[^>]+(>|$)/g, '').split('\n')) + .flat() + .join(' ') + + // TODO: Split after full word, not just within word. + if (excerpt.length > length) { + const trimmedExcerpt = excerpt.slice(0, length) + const lastSpaceIndex = trimmedExcerpt.lastIndexOf(' ') + + // Ensure we don't cut off mid-word + return trimmedExcerpt.slice(0, lastSpaceIndex) + ' ...' + } + + return excerpt +} diff --git a/blog/src/utils/readtime.ts b/blog/src/utils/readtime.ts new file mode 100644 index 00000000..448ab5ba --- /dev/null +++ b/blog/src/utils/readtime.ts @@ -0,0 +1,17 @@ +import MarkdownIt from 'markdown-it' +const parser = new MarkdownIt() + +const WORDS_PER_MINUTE = 150 + +export const calculateReadTime = (body: string): string => { + const excerpt = parser + .render(body) + .split('\n') + .slice(0, 6) + .map((str: string) => str.replace(/<\/?[^>]+(>|$)/g, '').split('\n')) + .flat() + .join(' ') + .split(' ') + + return (excerpt.length / WORDS_PER_MINUTE).toFixed(0) +} diff --git a/blog/tailwind.config.js b/blog/tailwind.config.mjs similarity index 86% rename from blog/tailwind.config.js rename to blog/tailwind.config.mjs index 461424c8..ea53e7e5 100644 --- a/blog/tailwind.config.js +++ b/blog/tailwind.config.mjs @@ -1,8 +1,8 @@ +/** @type {import('tailwindcss').Config} */ module.exports = { darkMode: 'class', content: [ - './src/**/*.{js,jsx,ts,tsx}', - './content/**/*.{md,mdx}', + './src/**/*.{astro,html,js,jsx,md,mdx,svelte,ts,tsx,vue}', ], theme: { fontFamily: { diff --git a/blog/tsconfig.json b/blog/tsconfig.json new file mode 100644 index 00000000..96e45dca --- /dev/null +++ b/blog/tsconfig.json @@ -0,0 +1,7 @@ +{ + "extends": "astro/tsconfigs/strict", + "compilerOptions": { + "jsx": "react-jsx", + "jsxImportSource": "@builder.io/qwik" + } +} \ No newline at end of file