website-content-updates #7

Open
caperren wants to merge 25 commits from website-content-updates into main
66 changed files with 1509 additions and 794 deletions
Showing only changes of commit 6f728ad146 - Show all commits

View File

@@ -0,0 +1,27 @@
name: Playwright Tests
on:
push:
branches: [ main, master ]
pull_request:
branches: [ main, master ]
jobs:
test:
timeout-minutes: 60
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: actions/setup-node@v4
with:
node-version: lts/*
- name: Install dependencies
run: npm ci
- name: Install Playwright Browsers
run: npx playwright install --with-deps
- name: Run Playwright tests
run: npx playwright test
- uses: actions/upload-artifact@v4
if: ${{ !cancelled() }}
with:
name: playwright-report
path: playwright-report/
retention-days: 30

7
.gitignore vendored
View File

@@ -28,3 +28,10 @@ pnpm-debug.log*
# jetbrains setting folder # jetbrains setting folder
.idea/ .idea/
# Playwright
/test-results/
/playwright-report/
/blob-report/
/playwright/.cache/
/playwright/.auth/

View File

@@ -5,7 +5,8 @@
fix \ fix \
astro_upgrade \ astro_upgrade \
build \ build \
dev dev \
dev-hosted
default: dev default: dev
@@ -24,3 +25,6 @@ build:
dev: dev:
npm run dev npm run dev
dev-hosted:
npm run dev-hosted

View File

@@ -1,6 +1,5 @@
// @ts-check // @ts-check
import { defineConfig } from 'astro/config'; import { defineConfig } from 'astro/config';
import rehypeAstroRelativeMarkdownLinks from "astro-rehype-relative-markdown-links";
import tailwindcss from "@tailwindcss/vite"; import tailwindcss from "@tailwindcss/vite";
@@ -8,10 +7,6 @@ import tailwindcss from "@tailwindcss/vite";
export default defineConfig({ export default defineConfig({
integrations: [], integrations: [],
markdown: {
rehypePlugins: [rehypeAstroRelativeMarkdownLinks],
},
vite: { vite: {
plugins: [tailwindcss()], plugins: [tailwindcss()],
}, },

View File

@@ -0,0 +1,8 @@
import { test, expect } from '@playwright/test';
test('Has Title', async ({ page }) => {
await page.goto('/');
// Expect a title "to contain" a substring.
await expect(page).toHaveTitle(/Corwin Perren/);
});

1473
package-lock.json generated

File diff suppressed because it is too large Load Diff

View File

@@ -4,15 +4,21 @@
"version": "0.0.1", "version": "0.0.1",
"scripts": { "scripts": {
"dev": "astro dev", "dev": "astro dev",
"dev-hosted": "astro dev --host",
"build": "astro build", "build": "astro build",
"preview": "astro preview", "preview": "astro preview",
"astro": "astro" "astro": "astro",
"test": "vitest"
}, },
"dependencies": { "dependencies": {
"@tailwindcss/vite": "^4.1.11", "@tailwindcss/vite": "^4.1.11",
"astro": "^5.11.0", "astro": "^5.15.3",
"astro-navbar": "^2.4.0", "flowbite": "^3.1.2",
"astro-rehype-relative-markdown-links": "^0.18.1",
"tailwindcss": "^4.1.11" "tailwindcss": "^4.1.11"
},
"devDependencies": {
"@playwright/test": "^1.56.1",
"@types/node": "^24.10.0",
"vitest": "^4.0.7"
} }
} }

79
playwright.config.ts Normal file
View File

@@ -0,0 +1,79 @@
import { defineConfig, devices } from '@playwright/test';
/**
* Read environment variables from file.
* https://github.com/motdotla/dotenv
*/
// import dotenv from 'dotenv';
// import path from 'path';
// dotenv.config({ path: path.resolve(__dirname, '.env') });
/**
* See https://playwright.dev/docs/test-configuration.
*/
export default defineConfig({
testDir: './e2e',
/* Run tests in files in parallel */
fullyParallel: true,
/* Fail the build on CI if you accidentally left test.only in the source code. */
forbidOnly: !!process.env.CI,
/* Retry on CI only */
retries: process.env.CI ? 2 : 0,
/* Opt out of parallel tests on CI. */
workers: process.env.CI ? 1 : undefined,
/* Reporter to use. See https://playwright.dev/docs/test-reporters */
reporter: 'html',
/* Shared settings for all the projects below. See https://playwright.dev/docs/api/class-testoptions. */
use: {
/* Base URL to use in actions like `await page.goto('')`. */
baseURL: 'http://localhost:4321',
/* Collect trace when retrying the failed test. See https://playwright.dev/docs/trace-viewer */
trace: 'on-first-retry',
},
/* Configure projects for major browsers */
projects: [
{
name: 'chromium',
use: { ...devices['Desktop Chrome'] },
},
// {
// name: 'firefox',
// use: { ...devices['Desktop Firefox'] },
// },
//
// {
// name: 'webkit',
// use: { ...devices['Desktop Safari'] },
// },
/* Test against mobile viewports. */
{
name: 'Mobile Chrome',
use: { ...devices['Pixel 5'] },
},
// {
// name: 'Mobile Safari',
// use: { ...devices['iPhone 12'] },
// },
/* Test against branded browsers. */
// {
// name: 'Microsoft Edge',
// use: { ...devices['Desktop Edge'], channel: 'msedge' },
// },
// {
// name: 'Google Chrome',
// use: { ...devices['Desktop Chrome'], channel: 'chrome' },
// },
],
/* Run your local dev server before starting the tests */
// webServer: {
// command: 'npm run start',
// url: 'http://localhost:3000',
// reuseExistingServer: !process.env.CI,
// },
});

View File

@@ -2,13 +2,14 @@
<!-- Created with Inkscape (http://www.inkscape.org/) --> <!-- Created with Inkscape (http://www.inkscape.org/) -->
<svg <svg
class="logo-title"
width="21.129419mm" width="21.129419mm"
height="9.3295746mm" height="9.3295746mm"
viewBox="0 0 74.868021 33.057548" viewBox="0 0 74.868021 33.057548"
id="svg4376" id="svg4376"
version="1.1" version="1.1"
inkscape:version="1.4.2 (ebf0e940d0, 2025-05-08)" inkscape:version="1.4.2 (ebf0e940d0, 2025-05-08)"
sodipodi:docname="AP in C Green Mock UP.svg" sodipodi:docname="logo-title.svg"
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape" xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd" xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
xmlns="http://www.w3.org/2000/svg" xmlns="http://www.w3.org/2000/svg"

Before

Width:  |  Height:  |  Size: 5.5 KiB

After

Width:  |  Height:  |  Size: 5.6 KiB

View File

@@ -1,5 +1,7 @@
--- ---
--- ---
<footer class="flex justify-center items-center text-center">
{import.meta.env.PUBLIC_BUILD_ENVIRONMENT || "development"} | {import.meta.env.PUBLIC_REPO_VERSION_HASH || "invalid"}@{import.meta.env.PUBLIC_PROJECT_VERSION || "0.0.0"} <footer class="fixed bottom-0 left-0 z-20 w-full px-6 py-2 bg-black border-t border-t-caperren-green text-caperren-green text-sm flex items-center justify-between">
<span>{import.meta.env.PUBLIC_BUILD_ENVIRONMENT || "development"}</span>
<span>{import.meta.env.PUBLIC_REPO_VERSION_HASH || "invalid"}@{import.meta.env.PUBLIC_PROJECT_VERSION || "0.0.0"}</span>
</footer> </footer>

View File

@@ -1,150 +1,27 @@
--- ---
import {Image} from 'astro:assets'; import NestedNavbarEntry from "@components/NestedNavbarEntries.astro";
import {Astronav, MenuItems, MenuIcon, Dropdown, DropdownItems} from "astro-navbar";
import logoTitle from "../assets/logo-title.svg"; import logoTitle from "@assets/logo-title.svg?raw";
import {siteLayout} from "@data/site-layout.ts";
const navItems = [
{name: 'Home', href: '/'},
{
name: 'Experience↓',
href: "#",
dropdown: [
{name: 'SpaceX - Hardware Test Engineer II', href: '/experience/spacex-hardware-test-engineer'},
{
name: 'SpaceX - Avionics Test Engineer (Intern)',
href: '/experience/spacex-avionics-test-engineer-intern'
},
{name: 'SARL - Automation Engineer (Student)', href: '/experience/sarl-automation-engineer-student'},
{
name: 'CEOAS OMG - Software/Electronics Engineer (Student)',
href: '/experience/ceoas-omg-software-electronics-engineer-student'
},
{
name: 'OSURC - Member/Officer/Sub-Team Lead (Student)',
href: '/experience/osurc-member-officer-sub-team-lead'
},
]
},
{name: 'Projects↓', href: '/project/project'},
{name: 'Hobbies↓', href: '/hobby/hobby'},
{name: 'Resume', href: '/resume'},
{name: 'Contact', href: '/contact'}
];
--- ---
<header class="navbar md:flex p-5 gap-5">
<Astronav> <nav class="border-b border-b-caperren-green text-caperren-green">
<div class="flex w-full justify-between"> <div class="flex flex-wrap items-center justify-between mx-auto p-6">
<a href="/"> <a href="/">
<Image src={logoTitle} alt="Logo Title" height="50" loading="eager"/> <Fragment class="logo-title" set:html={logoTitle}/>
</a> </a>
<div class="block md:hidden"> <button data-collapse-toggle="navbar-multi-level" type="button"
<MenuIcon class="w-4 h-4 text-gray-800"/> class="inline-flex items-center p-2 w-10 h-10 justify-center text-sm md:hidden focus:ring-2 focus:ring-caperren-green"
aria-controls="navbar-multi-level" aria-expanded="false">
<span class="sr-only">Open main menu</span>
<svg class="w-5 h-5" aria-hidden="true" xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 17 14">
<path stroke="currentColor" stroke-linecap="round" stroke-linejoin="round" stroke-width="2"
d="M1 1h15M1 7h15M1 13h15"/>
</svg>
</button>
<div class="hidden w-full md:block md:w-auto" id="navbar-multi-level">
<NestedNavbarEntry items={siteLayout}/>
</div> </div>
</div> </div>
<MenuItems class="hidden md:flex"> </nav>
<ul class="flex flex-col md:flex-row md:gap-5">
<li>
<a href="/">Home</a>
</li>
<!--<li>-->
<!-- <Dropdown class="group">-->
<!-- <button class="flex items-center">-->
<!-- <span> Experience </span>-->
<!-- <svg-->
<!-- xmlns="http://www.w3.org/2000/svg"-->
<!-- fill="none"-->
<!-- viewBox="0 0 24 24"-->
<!-- stroke-width="3"-->
<!-- stroke="currentColor"-->
<!-- class="w-3 h-3 mt-0.5 group-open:rotate-180">-->
<!-- <path-->
<!-- stroke-linecap="round"-->
<!-- stroke-linejoin="round"-->
<!-- d="M19.5 8.25l-7.5 7.5-7.5-7.5"></path>-->
<!-- </svg>-->
<!-- </button>-->
<!-- <DropdownItems class="relative">-->
<!-- <div class="bg-black px-1 py-2 absolute top-0">-->
<!-- <ul>-->
<!-- <li>-->
<!-- <a class="whitespace-nowrap" href="#">SpaceX</a>-->
<!-- </li>-->
<!-- <li>-->
<!-- <a class="whitespace-nowrap" href="#">Sinnhuber Aquatic Research Laboratory</a>-->
<!-- </li>-->
<!-- <li>-->
<!-- <a class="whitespace-nowrap" href="#">CEOAS Ocean Mixing Group</a>-->
<!-- </li>-->
<!-- </ul>-->
<!-- </div>-->
<!-- </DropdownItems>-->
<!-- </Dropdown>-->
<!--</li>-->
<!--<li>-->
<!-- <Dropdown class="group">-->
<!-- <button class="flex items-center">-->
<!-- <span> Projects </span>-->
<!-- <svg-->
<!-- xmlns="http://www.w3.org/2000/svg"-->
<!-- fill="none"-->
<!-- viewBox="0 0 24 24"-->
<!-- stroke-width="3"-->
<!-- stroke="currentColor"-->
<!-- class="w-3 h-3 mt-0.5 group-open:rotate-180">-->
<!-- <path-->
<!-- stroke-linecap="round"-->
<!-- stroke-linejoin="round"-->
<!-- d="M19.5 8.25l-7.5 7.5-7.5-7.5"></path>-->
<!-- </svg>-->
<!-- </button>-->
<!-- <DropdownItems class="relative">-->
<!-- <div class="bg-black absolute top-0">-->
<!-- <ul>-->
<!-- <li>-->
<!-- <a href="#">Placeholder 1</a>-->
<!-- </li>-->
<!-- </ul>-->
<!-- </div>-->
<!-- </DropdownItems>-->
<!-- </Dropdown>-->
<!--</li>-->
<!--<li>-->
<!-- <Dropdown class="group">-->
<!-- <button class="flex items-center">-->
<!-- <span> Hobbies </span>-->
<!-- <svg-->
<!-- xmlns="http://www.w3.org/2000/svg"-->
<!-- fill="none"-->
<!-- viewBox="0 0 24 24"-->
<!-- stroke-width="3"-->
<!-- stroke="currentColor"-->
<!-- class="w-3 h-3 mt-0.5 group-open:rotate-180">-->
<!-- <path-->
<!-- stroke-linecap="round"-->
<!-- stroke-linejoin="round"-->
<!-- d="M19.5 8.25l-7.5 7.5-7.5-7.5"></path>-->
<!-- </svg>-->
<!-- </button>-->
<!-- <DropdownItems class="relative">-->
<!-- <div class="bg-black absolute top-0">-->
<!-- <ul>-->
<!-- <li>Menu 1</li>-->
<!-- <li>Menu 2</li>-->
<!-- <li>Menu 3</li>-->
<!-- </ul>-->
<!-- </div>-->
<!-- </DropdownItems>-->
<!-- </Dropdown>-->
<!--</li>-->
<!--<li>-->
<!-- <a href="/resume">Resume</a>-->
<!--</li>-->
<li>
<a href="/contact">Contact</a>
</li>
</ul>
</MenuItems>
</Astronav>
</header>

View File

@@ -0,0 +1,47 @@
---
import type {navLink} from "@interfaces/site-layout.ts";
const items: navLink[] = Astro.props.items;
const depth: number = Astro.props.depth ?? 0;
const paths: string[] = Astro.props.paths ?? [];
const getNavLinkSuffix = (entry: navLink): string => {
return "-" + [...paths, entry.path].join("-")
}
const getHrefPath = (entry: navLink): string => {
return entry.pubpath ? entry.pubpath : ("/" + (paths && paths.length ? [...paths, entry.path].join("/") : entry.path));
}
---
<ul class={"flex flex-col p-4 bg-black border-caperren-green " + (depth ? "" : "md:flex-row md:space-x-8 md:mt-0")}>
{
items.map((entry, index) => (
<li >
{Array.isArray(entry.children) && entry.children.length ? (
<button id={"dropdownNavbarLink" + getNavLinkSuffix(entry)}
data-dropdown-toggle={"dropdownNavbar" + getNavLinkSuffix(entry)}
data-dropdown-placement="bottom"
class="flex items-center justify-between py-2 px-3 w-full hover:text-caperren-green-light md:hover:bg-transparent md:border-0 md:hover:text-caperren-green-light md:p-0 ">
{entry.title}
<svg class="w-2.5 h-2.5 ms-2.5" aria-hidden="true" xmlns="http://www.w3.org/2000/svg"
fill="none" viewBox="0 0 10 6">
<path stroke="currentColor" stroke-linecap="round" stroke-linejoin="round"
stroke-width="2"
d="m1 1 4 4 4-4"/>
</svg>
</button>
<div id={"dropdownNavbar" + getNavLinkSuffix(entry)}
class="z-10 hidden bg-black border border-caperren-green shadow-sm w-screen md:w-max">
<Astro.self items={entry.children} paths={[...paths, entry.path]} depth={depth + 1}/>
</div>
) : (
<a href={getHrefPath(entry)}
class="block py-2 px-3 bg-transparent hover:text-caperren-green-light ring-caperren-green-dark md:p-0"
aria-current="page">{entry.title}</a>
)}
</li>
))}
</ul>

151
src/data/site-layout.ts Normal file
View File

@@ -0,0 +1,151 @@
import type {navLink} from "@interfaces/site-layout.ts"
export const siteLayout: navLink[] = [
{title: "About", path: ""},
{
title: "Experiences",
path: "experience",
children: [
{
title: "SpaceX",
path: "spacex",
children: [
{
title: "Hardware Test Engineer I/II",
path: "hardware-test-engineer-i-ii"
},
{
title: "Avionics Test Engineering Internship",
path: "avionics-test-engineering-internship"
}
]
},
{
title: "OSU CEOAS",
path: "osu-ceoas-ocean-mixing-group",
children: [
{
title: "Robotics Oceanographic Surface Sampler",
path: "robotic-oceanographic-surface-sampler",
},
{
title: "LeConte Glacier Deployments",
path: "leconte-glacier-deployments",
}
]
},
{
title: "OSU SARL",
path: "osu-sinnhuber-aquatic-research-laboratory",
children: [
{
title: "Team Lead",
path: "team-lead",
},
{
title: "Zebrafish Embryo Pick and Plate",
path: "zebrafish-embryo-pick-and-plate",
},
{
title: "Shuttlebox Behavior System",
path: "shuttlebox-behavior-system",
},
{
title: "Dechorionator",
path: "dechorionator",
},
{
title: "Denso Embryo Pick and Plate",
path: "denso-embryo-pick-and-plate",
},
{
title: "ZScan Processor",
path: "zscan-processor",
}
]
},
{
title: "OSU Robotics Club",
path: "osu-robotics-club",
children: [
{
title: "Club Officer",
path: "club-officer",
},
{
title: "Mars Rover Software Team Lead",
path: "mars-rover-software-team-lead",
},
{
title: "Mars Rover Emergency Software Team Lead",
path: "mars-rover-emergency-software-team-lead",
},
{
title: "Mars Rover Electrical Team Lead",
path: "mars-rover-electrical-team-lead",
}
]
},
]
},
{
title: "Hobbies",
path: "hobby",
children: [
{
title: "Homelab", path: "homelab",
children: [
{title: "Home Server Rack", path: "home-server-rack"},
{title: "Offsite Backup Rack", path: "offsite-backup-rack"},
{title: "Kubernetes Cluster", path: "kubernetes-cluster"},
{title: "Home Automation", path: "home-automation"},
]
},
{
title: "Motorcycling",
path: "motorcycling",
children: [
{title: "Lineup", path: "lineup"},
{
title: "Custom Accessories",
path: "custom-accessories",
children: [
{title: "Chubby Buttons 2 Mount", path: "chubby-buttons-2-mount"},
]
},
{
title: "Trips",
path: "trips",
children: [
{title: "2025-08 | Alaska ", path: "2025-08-alaska"},
{title: "2024-10 | Norway ", path: "2024-10-norway"}
]
},
]
},
{
title: "Homelab", path: "homelab",
children: [
{title: "Home Server Rack", path: "home-server-rack"},
{title: "Offsite Backup Rack", path: "offsite-backup-rack"},
{title: "Kubernetes Cluster", path: "kubernetes-cluster"},
{title: "Home Automation", path: "home-automation"},
]
},
{title: "NixOS", path: "nixos"},
{title: "Body Mods", path: "body-mods"},
]
},
{
title: "Resumes",
path: "resume",
children: [
{title: "2025-11-10 | Complete CV", path: "2025-11-10-complete-cv"},
{title: "2025-11-10 | Infrastructure Engineer", path: "2025-11-10-infrastructure-engineer"},
{title: "2019-07-01 | Hardware Test Engineer", path: "2019-07-01-hardware-test-engineer"},
]
},
{title: "Github", pubpath: "https://github.com/caperren"},
{title: "LinkedIn", pubpath: "https://www.linkedin.com/in/caperren/"}
]

View File

@@ -0,0 +1,6 @@
export interface navLink {
title: string;
path?: string;
pubpath?: string;
children?: navLink[];
}

View File

@@ -9,15 +9,17 @@ const pageTitle = Astro.props.title ? `${Astro.props.title} - Corwin Perren` : "
<html lang="en"> <html lang="en">
<head> <head>
<meta charset="UTF-8"/> <meta charset="UTF-8"/>
<link rel="icon" href="/favicon.svg" type="image/svg+xml" /> <link rel="icon" href="/favicon.svg" type="image/svg+xml"/>
<meta name="viewport" content="width=device-width, initial-scale=1.0"/> <meta name="viewport" content="width=device-width, initial-scale=1.0"/>
<title>{pageTitle}</title> <title>{pageTitle}</title>
</head> </head>
<body> <body class="bg-black text-white">
<Navbar/> <Navbar/>
<main style="padding: 2rem;"> <main class="mx-6 mt-6 mb-14">
<slot/> <slot/>
</main> </main>
<Footer/> <Footer/>
</body> </body>
</html> </html>
<script is:inline type="module" src="/src/scripts/main.js"></script>

View File

@@ -0,0 +1,6 @@
---
import BaseLayout from './BaseLayout.astro';
---
<BaseLayout>
<slot/>
</BaseLayout>

View File

@@ -0,0 +1,10 @@
---
import BaseLayout from './BaseLayout.astro';
const resume = Astro.props.resume;
---
<BaseLayout>
<div class="h-dvh">
<iframe src={resume} class="mx-auto w-9/10 md:w-3/5 h-7/10 md:h-4/5"/>
</div>
</BaseLayout>

View File

@@ -0,0 +1,6 @@
---
import ExperienceLayout from "@layouts/ExperienceLayout.astro";
---
<ExperienceLayout>
</ExperienceLayout>

View File

@@ -0,0 +1,6 @@
---
import ExperienceLayout from "@layouts/ExperienceLayout.astro";
---
<ExperienceLayout>
</ExperienceLayout>

View File

@@ -0,0 +1,6 @@
---
import ExperienceLayout from "@layouts/ExperienceLayout.astro";
---
<ExperienceLayout>
</ExperienceLayout>

View File

@@ -0,0 +1,6 @@
---
import ExperienceLayout from "@layouts/ExperienceLayout.astro";
---
<ExperienceLayout>
</ExperienceLayout>

View File

@@ -0,0 +1,6 @@
---
import ExperienceLayout from "@layouts/ExperienceLayout.astro";
---
<ExperienceLayout>
</ExperienceLayout>

View File

@@ -0,0 +1,6 @@
---
import ExperienceLayout from "@layouts/ExperienceLayout.astro";
---
<ExperienceLayout>
</ExperienceLayout>

View File

@@ -0,0 +1,6 @@
---
import ExperienceLayout from "@layouts/ExperienceLayout.astro";
---
<ExperienceLayout>
</ExperienceLayout>

View File

@@ -0,0 +1,6 @@
---
import ExperienceLayout from "@layouts/ExperienceLayout.astro";
---
<ExperienceLayout>
</ExperienceLayout>

View File

@@ -0,0 +1,6 @@
---
import ExperienceLayout from "@layouts/ExperienceLayout.astro";
---
<ExperienceLayout>
</ExperienceLayout>

View File

@@ -0,0 +1,6 @@
---
import ExperienceLayout from "@layouts/ExperienceLayout.astro";
---
<ExperienceLayout>
</ExperienceLayout>

View File

@@ -0,0 +1,6 @@
---
import ExperienceLayout from "@layouts/ExperienceLayout.astro";
---
<ExperienceLayout>
</ExperienceLayout>

View File

@@ -0,0 +1,6 @@
---
import ExperienceLayout from "@layouts/ExperienceLayout.astro";
---
<ExperienceLayout>
</ExperienceLayout>

View File

@@ -1,9 +0,0 @@
---
import ExperienceLayout from '../../../layouts/ExperienceLayout.astro';
import {Image} from 'astro:assets';
import spring_2019_interns from "../../../assets/experience/spacex/avionics-test-engineering-intern/spring-2019-interns.jpg";
---
<ExperienceLayout>
<Image class="mx-auto block" src={spring_2019_interns} alt="spring-2019-interns.jpg" loading="eager"/>
</ExperienceLayout>

View File

@@ -0,0 +1,11 @@
---
import ExperienceLayout from '@layouts/ExperienceLayout.astro';
import {Image} from 'astro:assets';
import spring_2019_interns from "@assets/experience/spacex/avionics-test-engineering-internship/spring-2019-interns.jpg";
---
<ExperienceLayout>
<Image class="mx-auto block" src={spring_2019_interns} alt="spring-2019-interns.jpg" loading="eager"/>
<span>Final text here</span>
</ExperienceLayout>

View File

@@ -0,0 +1,13 @@
---
import ExperienceLayout from '@layouts/ExperienceLayout.astro';
import {Image} from 'astro:assets';
import starlink_headquarters_selfie from "@assets/experience/spacex/hardware-test-engineer-i-ii/starlink_headquarters_selfie.jpg";
---
<ExperienceLayout title="SpaceX - Hardware Test Engineer II" >
<Image class="mx-auto block" src={starlink_headquarters_selfie} alt="starlink_headquarters_selfie" loading="eager"/>
<h2 >Timeline</h2>
<ul>
<li>Test</li>
</ul>
</ExperienceLayout>

View File

@@ -1,9 +0,0 @@
---
import ExperienceLayout from '../../../layouts/ExperienceLayout.astro';
import {Image} from 'astro:assets';
import starlink_headquarters_selfie from "../../../assets/experience/spacex/hardware-test-engineer-ii/starlink_headquarters_selfie.jpg";
---
<ExperienceLayout>
<Image class="mx-auto block" src={starlink_headquarters_selfie} alt="starlink_headquarters_selfie" loading="eager"/>
</ExperienceLayout>

View File

@@ -0,0 +1,6 @@
---
import HobbyLayout from "@layouts/HobbyLayout.astro";
---
<HobbyLayout>
</HobbyLayout>

View File

@@ -0,0 +1,6 @@
---
import HobbyLayout from "@layouts/HobbyLayout.astro";
---
<HobbyLayout>
</HobbyLayout>

View File

@@ -0,0 +1,6 @@
---
import HobbyLayout from "@layouts/HobbyLayout.astro";
---
<HobbyLayout>
</HobbyLayout>

View File

@@ -0,0 +1,6 @@
---
import HobbyLayout from "@layouts/HobbyLayout.astro";
---
<HobbyLayout>
</HobbyLayout>

View File

@@ -0,0 +1,6 @@
---
import HobbyLayout from "@layouts/HobbyLayout.astro";
---
<HobbyLayout>
</HobbyLayout>

View File

@@ -1,2 +0,0 @@
---
---

View File

@@ -0,0 +1,6 @@
---
import HobbyLayout from "@layouts/HobbyLayout.astro";
---
<HobbyLayout>
</HobbyLayout>

View File

@@ -0,0 +1,6 @@
---
import HobbyLayout from "@layouts/HobbyLayout.astro";
---
<HobbyLayout>
</HobbyLayout>

View File

@@ -0,0 +1,6 @@
---
import HobbyLayout from "@layouts/HobbyLayout.astro";
---
<HobbyLayout>
</HobbyLayout>

View File

@@ -0,0 +1,6 @@
---
import HobbyLayout from "@layouts/HobbyLayout.astro";
---
<HobbyLayout>
</HobbyLayout>

View File

@@ -0,0 +1,6 @@
---
import HobbyLayout from "@layouts/HobbyLayout.astro";
---
<HobbyLayout>
</HobbyLayout>

View File

@@ -1,6 +0,0 @@
---
import BaseLayout from '../layouts/BaseLayout.astro';
---
<BaseLayout>
</BaseLayout>

View File

@@ -0,0 +1,6 @@
---
import ResumeLayout from "@layouts/ResumeLayout.astro";
import resume from "@assets/resume/corwin_perren_2019-07-01_hardware_test_engineer.pdf"
---
<ResumeLayout resume={resume}/>

View File

@@ -0,0 +1,5 @@
---
import ResumeLayout from "@layouts/ResumeLayout.astro";
---
<ResumeLayout/>

View File

@@ -0,0 +1,6 @@
---
import ResumeLayout from "@layouts/ResumeLayout.astro";
import resume from "@assets/resume/corwin_perren_2025_10_27_infrastructure_engineer.pdf"
---
<ResumeLayout resume={resume}/>

1
src/scripts/main.js Normal file
View File

@@ -0,0 +1 @@
import 'flowbite';

View File

@@ -1,33 +1,13 @@
@import "tailwindcss"; @import "tailwindcss";
@import "flowbite/src/themes/default.css";
@plugin "flowbite/plugin";
@source "../../node_modules/flowbite";
@theme { @theme {
--default-font-family: font-mono;
--color-caperren-green: #10ac25; --color-caperren-green: #10ac25;
--color-caperren-green-light: #00ff2a;
--color-caperren-green-dark: #06370e;
} }
body {
margin: 0;
font-family: system-ui, sans-serif;
background-color: #000000;
color: var(--color-caperren-green);
}
a {
color: var(--color-caperren-green);
text-decoration: none;
}
.navbar {
align-items: center;
background-color: #000000;
border-bottom: 2px solid var(--color-caperren-green);
}
.navbar a, .navbar span {
font-weight: bold;
white-space: nowrap;
}
footer {
border-top: 2px solid var(--color-caperren-green);
}
/*.astronav-dropdown .group {*/
/* background-color: black;*/
/*}*/

View File

@@ -0,0 +1,15 @@
import { experimental_AstroContainer as AstroContainer } from 'astro/container';
import { expect, test } from 'vitest';
import Navbar from "@components/Navbar.js"
test('Card with slots', async () => {
const container = await AstroContainer.create();
const result = await container.renderToString(Card, {
slots: {
default: 'Card content',
},
});
expect(result).toContain('This is a card');
expect(result).toContain('Card content');
});

View File

@@ -1,4 +1,14 @@
{ {
"compilerOptions": {
"paths": {
"@assets/*": ["./src/assets/*"],
"@components/*": ["./src/components/*"],
"@data/*": ["./src/data/*"],
"@interfaces/*": ["./src/interfaces/*"],
"@layouts/*": ["./src/layouts/*"]
}
},
"extends": "astro/tsconfigs/strict", "extends": "astro/tsconfigs/strict",
"include": [".astro/types.d.ts", "**/*"], "include": [".astro/types.d.ts", "**/*"],
"exclude": ["dist"] "exclude": ["dist"]

15
vitest.config.ts Normal file
View File

@@ -0,0 +1,15 @@
/// <reference types="vitest" />
import {getViteConfig} from 'astro/config';
export default getViteConfig(
{
test: {
/* for example, use global to avoid globals imports (describe, test, expect): */
// globals: true,
},
},
{
site: 'https://caperren.com/',
trailingSlash: 'always',
},
);