Compare commits

...

58 Commits
0.1.2 ... 0.6.6

Author SHA1 Message Date
369e97af41 bump package image
Some checks failed
release-image-gitea / release (push) Successful in 54s
release-image-harbor / release (push) Failing after 52s
2025-03-14 22:37:55 -05:00
754ff5d9a9 add harbor 2025-03-14 22:37:03 -05:00
351cac00b3 use k8 driver 2025-03-14 22:20:45 -05:00
11c85e324e remove container 2025-03-14 21:52:01 -05:00
5a418428d3 change config 2025-03-14 21:26:34 -05:00
3d4c9c2214 remove verify 2025-03-14 21:16:17 -05:00
10262c4b7a remove certs 2025-03-14 21:15:07 -05:00
57ea8374a5 change workflow 2025-03-14 21:13:27 -05:00
e9e1cabd11 add podman 2025-03-14 21:04:35 -05:00
4c1ec680a9 use buildah 2025-03-14 20:58:33 -05:00
4f826e8964 add build step 2025-03-14 20:43:18 -05:00
3ddce86e64 change config 2025-03-14 20:32:49 -05:00
61aa06310c update 2025-03-14 20:15:23 -05:00
03195017c5 update version 2025-03-14 16:56:25 -05:00
fc3f4fdad4 fix workflow 2025-03-14 16:52:43 -05:00
fc42f31fb0 update images 2025-03-14 16:51:34 -05:00
renovate[bot]
e56b3a001e Update docker/build-push-action digest to 0adf995 (#38)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-02-19 23:17:00 -06:00
renovate[bot]
13711618b7 Update docker/build-push-action digest to 67a2d40 (#35)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-01-17 17:17:55 -06:00
04980a38af update tag 2025-01-09 21:31:14 -06:00
385ad20c82 update lock 2025-01-09 21:26:35 -06:00
761652f46d update dependencies 2025-01-09 21:25:00 -06:00
renovate[bot]
8f6b1af8ad Update docker/metadata-action digest to 8e1d546 (#32)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-01-09 21:17:30 -06:00
renovate[bot]
90c8d30e3f Update docker/login-action digest to 327cd5a (#31)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-01-09 21:17:19 -06:00
renovate[bot]
ad9128acea Update docker/build-push-action digest to 31ca4e5 (#29)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-01-09 21:16:45 -06:00
renovate[bot]
5f9235c9dc Migrate config .github/renovate.json (#27)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2024-12-21 19:53:06 -06:00
renovate[bot]
3b2702af36 Update renovate/renovate Docker tag to v39 (#24)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2024-12-21 19:52:28 -06:00
renovate[bot]
f999b9a92c Update docker/metadata-action digest to 906ecf0 (#21)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2024-12-21 19:50:40 -06:00
renovate[bot]
35c940bef7 Update docker/build-push-action digest to 7e09459 (#20)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2024-12-21 19:50:36 -06:00
renovate[bot]
7aa6898a93 Update docker/login-action digest to 7ca3450 (#15)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2024-12-21 19:50:29 -06:00
9d77c9db2a update dependencies 2024-12-21 19:48:14 -06:00
528eb8fb2e update lockfile 2024-09-30 17:15:52 -05:00
14e73d61ef update dependencies 2024-09-30 17:13:16 -05:00
renovate[bot]
d10fe280a5 Update dependency @astrojs/node to v8.3.4 (#12)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2024-09-30 17:08:27 -05:00
renovate[bot]
5ea5774042 Update docker/build-push-action digest to 4f58ea7 (#13)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2024-09-30 17:08:15 -05:00
renovate[bot]
3c82fb43d8 Update docker/login-action digest to 3b8fed7 (#10)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2024-09-30 17:07:40 -05:00
renovate[bot]
c7071ab583 Update docker/metadata-action digest to 70b2cdc (#11)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2024-09-30 17:07:27 -05:00
renovate[bot]
125d70d62e Update dependency typescript to v5.6.2 (#9)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2024-09-30 17:07:15 -05:00
renovate[bot]
357634d3f0 Update dependency @directus/sdk to v17.0.1 (#8)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2024-09-30 17:06:28 -05:00
renovate[bot]
bd4b85c874 Update dependency astro to v4.14.6 (#6)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2024-09-30 16:23:34 -05:00
7efa375427 remove author field 2024-08-24 02:09:34 -05:00
358d6b91c6 upgrade base image 2024-08-24 01:35:22 -05:00
92d4be91df upgrade astro 2024-08-24 01:34:16 -05:00
0f5fc27371 convert to use directus 2024-08-24 01:23:12 -05:00
fd85557d6b replace placeholder info with my own 2024-08-23 22:01:12 -05:00
f6c05b8a0c change work to projects 2024-08-23 21:01:26 -05:00
b8efef1a00 polishing pass 2024-08-23 20:46:46 -05:00
ad88da00e6 enable hyrbide rendering 2024-08-23 00:13:47 -05:00
ff50ff7e9a remove main release 2024-08-19 21:57:31 -05:00
a37da0c6ed add gitignore 2024-08-19 21:49:57 -05:00
5dfe806e6b remove default content and replace with myself 2024-08-19 21:47:37 -05:00
7ef4b48b18 add directus
Some checks failed
release-image / release-image (push) Has been cancelled
2024-08-19 21:31:24 -05:00
d321c805e1 bump version 2024-08-19 17:21:25 -05:00
ba28de9f61 change tags in release workflow 2024-08-19 17:19:56 -05:00
29bdf18fd6 change release workflow 2024-08-19 17:17:33 -05:00
3d5a1e12c0 bump docker tag 2024-08-19 17:15:19 -05:00
75284a9696 add labels 2024-08-19 17:11:51 -05:00
2701cbe8c5 fix lock file 2024-08-19 17:08:56 -05:00
e055360b68 used staged docker build 2024-08-19 17:03:41 -05:00
43 changed files with 1733 additions and 2239 deletions

View File

@@ -0,0 +1,58 @@
name: release-image-gitea
on:
push:
tags:
- 0.*
workflow_dispatch:
jobs:
release:
runs-on: ubuntu-latest
steps:
- name: Checkout
uses: actions/checkout@v4
- name: Create Kubeconfig
run: |
mkdir $HOME/.kube
echo "${{ secrets.KUBECONFIG_BUILDX }}" > $HOME/.kube/config
- name: Set up Docker Buildx
id: buildx
uses: docker/setup-buildx-action@v3
with:
driver: kubernetes
driver-opts: |
namespace=gitea
qemu.install=true
- name: Available Platforms
run: echo ${{ steps.buildx.outputs.platforms }}
- name: Login to Registry
uses: docker/login-action@v3
with:
registry: ${{ vars.REPOSITORY_HOST }}
username: ${{ gitea.actor }}
password: ${{ secrets.REPOSITORY_TOKEN }}
- name: Extract Metadata
id: meta
uses: docker/metadata-action@v5
with:
tags: |
type=ref,event=branch
type=ref,event=tag
images: ${{ vars.REPOSITORY_HOST }}/${{ gitea.repository }}
- name: Build and Push Image
uses: docker/build-push-action@v6
with:
context: .
push: true
platforms: linux/amd64
tags: ${{ steps.meta.outputs.tags }}
labels: ${{ steps.meta.outputs.labels }}
file: ./Dockerfile

View File

@@ -0,0 +1,58 @@
name: release-image-harbor
on:
push:
tags:
- 0.*
workflow_dispatch:
jobs:
release:
runs-on: ubuntu-latest
steps:
- name: Checkout
uses: actions/checkout@v4
- name: Create Kubeconfig
run: |
mkdir $HOME/.kube
echo "${{ secrets.KUBECONFIG_BUILDX }}" > $HOME/.kube/config
- name: Set up Docker Buildx
id: buildx
uses: docker/setup-buildx-action@v3
with:
driver: kubernetes
driver-opts: |
namespace=gitea
qemu.install=true
- name: Available Platforms
run: echo ${{ steps.buildx.outputs.platforms }}
- name: Login to Registry
uses: docker/login-action@v3
with:
registry: ${{ vars.REGISTRY_HOST }}
username: ${{ vars.REGISTRY_USER }}
password: ${{ secrets.REGISTRY_SECRET }}
- name: Extract Metadata
id: meta
uses: docker/metadata-action@v5
with:
tags: |
type=ref,event=branch
type=ref,event=tag
images: ${{ vars.REGISTRY_HOST }}/images
- name: Build and Push Image
uses: docker/build-push-action@v6
with:
context: .
push: true
platforms: linux/amd64
tags: ${{ steps.meta.outputs.tags }}
labels: ${{ steps.meta.outputs.labels }}
file: ./Dockerfile

View File

@@ -1,2 +0,0 @@
# This file is processed by Renovate bot so that it creates a PR on new major Renovate versions
FROM renovate/renovate:38

44
.github/renovate.json vendored
View File

@@ -1,44 +0,0 @@
{
"$schema": "https://docs.renovatebot.com/renovate-schema.json",
"extends": [
"config:recommended",
"mergeConfidence:all-badges",
":rebaseStalePrs"
],
"timezone": "US/Central",
"schedule": [
"every weekday"
],
"labels": [],
"prHourlyLimit": 0,
"prConcurrentLimit": 0,
"packageRules": [
{
"description": "Disables for non major Renovate version",
"matchPaths": [
".github/renovate-update-notification/Dockerfile"
],
"matchUpdateTypes": [
"minor",
"patch",
"pin",
"digest",
"rollback"
],
"enabled": false
},
{
"description": "Generate for major Renovate version",
"matchPaths": [
".github/renovate-update-notification/Dockerfile"
],
"matchUpdateTypes": [
"major"
],
"addLabels": [
"upgrade"
],
"automerge": false
}
]
}

View File

@@ -1,47 +0,0 @@
name: release-image
on:
push:
branches:
- main
tags:
- 6.*
env:
REGISTRY: ghcr.io
IMAGE_NAME: ${{ github.repository }}
jobs:
release-image:
permissions:
contents: read
packages: write
runs-on: ubuntu-latest
steps:
- name: Checkout repository
uses: actions/checkout@v4
- name: Log into the container registry
uses: docker/login-action@9780b0c442fbb1117ed29e0efdff1e18412f7567
with:
registry: ${{ env.REGISTRY }}
username: ${{ github.actor }}
password: ${{ secrets.GITHUB_TOKEN }}
- name: Extract metadata for Docker
id: meta
uses: docker/metadata-action@60a0d343a0d8a18aedee9d34e62251f752153bdb
with:
tags: |
type=ref,event=branch
type=ref,event=tag
images: ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}
- name: Build and push Docker image
uses: docker/build-push-action@5cd11c3a4ced054e52742c5fd54dca954e0edd85
with:
context: .
push: true
tags: ${{ steps.meta.outputs.tags }}
labels: ${{ steps.meta.outputs.labels }}
file: ./Dockerfile

5
.gitignore vendored
View File

@@ -22,3 +22,8 @@ pnpm-debug.log*
# jetbrains setting folder
.idea/
# ide
.vscode/
site-profile.code-workspace
.pre-commit-config.yaml

View File

@@ -1,22 +1,30 @@
FROM node:20.16.0-alpine3.20 AS base
FROM node:22.14.0-alpine3.20 AS base
LABEL version="0.6.6"
LABEL description="Astro based website to use as a personal site"
ENV PNPM_HOME="/pnpm"
ENV PATH="$PNPM_HOME:$PATH"
RUN corepack enable
WORKDIR /app
COPY . .
COPY package.json pnpm-lock.yaml ./
FROM base AS prod-deps
RUN --mount=type=cache,id=pnpm,target=/pnpm/store pnpm install --prod --frozen-lockfile
FROM base AS build
FROM prod-deps AS build-deps
RUN --mount=type=cache,id=pnpm,target=/pnpm/store pnpm install --frozen-lockfile
FROM build-deps AS build
COPY . .
RUN pnpm run build
FROM base
FROM base AS runtime
COPY --from=prod-deps /app/node_modules /app/node_modules
COPY --from=build /app/dist /app/dist
ENV HOST=0.0.0.0
ENV PORT=4321
EXPOSE 4321

View File

@@ -1,6 +1,6 @@
MIT License
Copyright (c) 2024 Alex Lebens
Copyright (c) 2025 Alex Lebens
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal

View File

@@ -1 +1,30 @@
# Profile
# Astro Starter Kit: Portfolio
```sh
pnpm create astro@latest -- --template portfolio
```
[![Open in StackBlitz](https://developer.stackblitz.com/img/open_in_stackblitz.svg)](https://stackblitz.com/github/withastro/astro/tree/latest/examples/portfolio)
[![Open with CodeSandbox](https://assets.codesandbox.io/github/button-edit-lime.svg)](https://codesandbox.io/p/sandbox/github/withastro/astro/tree/latest/examples/portfolio)
[![Open in GitHub Codespaces](https://github.com/codespaces/badge.svg)](https://codespaces.new/withastro/astro?devcontainer_path=.devcontainer/portfolio/devcontainer.json)
> 🧑‍🚀 **Seasoned astronaut?** Delete this file. Have fun!
![portfolio](https://user-images.githubusercontent.com/357379/210779178-a98f0fb7-6b1a-4068-894c-8e1403e26654.jpg)
## 🧞 Commands
All commands are run from the root of the project, from a terminal:
| Command | Action |
| :------------------------ | :----------------------------------------------- |
| `pnpm install` | Installs dependencies |
| `pnpm dev` | Starts local dev server at `localhost:4321` |
| `pnpm build` | Build your production site to `./dist/` |
| `pnpm preview` | Preview your build locally, before deploying |
| `pnpm astro ...` | Run CLI commands like `astro add`, `astro check` |
| `pnpm 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).

View File

@@ -2,9 +2,8 @@ import { defineConfig } from 'astro/config';
import node from "@astrojs/node";
// https://astro.build/config
export default defineConfig({
output: "server",
output: "static",
adapter: node({
mode: "standalone"
})

50
lib/directus.ts Normal file
View File

@@ -0,0 +1,50 @@
import { createDirectus, rest, } from '@directus/sdk';
type Global = {
title: string;
description: string;
name: string;
tagline: string;
email: string;
portrait: string;
about: string;
}
type About = {
background: string;
experience: string;
education: string;
certifications: string;
}
type Skills = {
skill_1: string;
skill_1_description: string;
skill_2: string;
skill_2_description: string;
skill_3: string;
skill_3_description: string;
}
export type Post = {
slug: string;
title: string;
content: string;
image: string;
image_alt: string;
published_date: string;
tags: string[];
}
type Schema = {
global: Global;
about: About;
skills: Skills;
posts: Post[];
}
export const directus_url = "https://directus.alexlebens.dev"
const directus = createDirectus<Schema>(directus_url).with(rest());
export default directus;

View File

@@ -1,18 +1,18 @@
{
"name": "",
"name": "site-profile",
"type": "module",
"version": "0.0.1",
"version": "0.6.6",
"scripts": {
"dev": "astro dev",
"start": "astro dev",
"build": "astro check && astro build",
"build": "astro build",
"preview": "astro preview",
"astro": "astro"
},
"dependencies": {
"@astrojs/check": "^0.9.3",
"@astrojs/node": "^8.3.3",
"astro": "^4.14.2",
"typescript": "^5.5.4"
"@astrojs/check": "^0.9.4",
"@astrojs/node": "^9.1.3",
"@directus/sdk": "^19.0.1",
"astro": "^5.5.2",
"typescript": "^5.8.2"
}
}

3083
pnpm-lock.yaml generated

File diff suppressed because it is too large Load Diff

Binary file not shown.

Before

Width:  |  Height:  |  Size: 98 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 128 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 38 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 20 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 21 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 27 KiB

16
renovate.json Normal file
View File

@@ -0,0 +1,16 @@
{
"$schema": "https://docs.renovatebot.com/renovate-schema.json",
"extends": [
"config:recommended",
"mergeConfidence:all-badges",
":rebaseStalePrs"
],
"timezone": "US/Central",
"schedule": [
"every weekday"
],
"labels": [],
"prHourlyLimit": 0,
"prConcurrentLimit": 0,
"packageRules": []
}

View File

@@ -32,7 +32,6 @@ const { href } = Astro.props;
}
}
/* Overlay for hover effects. */
a::after {
content: '';
position: absolute;

View File

@@ -1,11 +1,16 @@
---
import CallToAction from './CallToAction.astro';
import Icon from './Icon.astro';
import directus from "../../lib/directus"
import { readSingleton } from "@directus/sdk";
const global = await directus.request(readSingleton("global"));
---
<aside>
<h2>Interested in working together?</h2>
<CallToAction href="mailto:me@example.com">
<CallToAction href=`mailto:${global.email}`>
Send Me a Message
<Icon icon="paper-plane-tilt" size="1.2em" />
</CallToAction>

View File

@@ -1,22 +1,27 @@
---
import Icon from './Icon.astro';
const currentYear = new Date().getFullYear();
import directus from "../../lib/directus"
import { readSingleton } from "@directus/sdk";
const global = await directus.request(readSingleton("global"));
---
<footer>
<div class="group">
<p>
Designed & Developed in Portland with <a href="https://astro.build/">Astro</a>
Designed & Developed in Minnesota with <a href="https://astro.build/">Astro</a>
<Icon icon="rocket-launch" size="1.2em" />
</p>
<p>&copy; {currentYear} Jeanine White</p>
<p>&copy; {currentYear} {global.name}</p>
</div>
<p class="socials">
<a href="https://twitter.com/me"> Twitter</a>
<a href="https://github.com/me"> GitHub</a>
<a href="https://codepen.io/me"> CodePen</a>
<a href="https://github.com/alexlebens"> GitHub</a>
<a href="https://www.linkedin.com/in/alexanderlebens"> LinkedIn</a>
</p>
</footer>
<style>
footer {
display: flex;

View File

@@ -24,7 +24,6 @@ const { variant } = Astro.props;
gap: 1.5rem;
}
/* If last row contains only one item, make it span both columns. */
.grid.small > :global(:last-child:nth-child(odd)) {
grid-column: 1 / 3;
}
@@ -40,12 +39,10 @@ const { variant } = Astro.props;
padding-bottom: var(--row-offset);
}
/* Shift first item in each row vertically to create staggered effect. */
.grid.offset > :global(:nth-child(odd)) {
transform: translateY(var(--row-offset));
}
/* If last row contains only one item, display it in the second column. */
.grid.offset > :global(:last-child:nth-child(odd)) {
grid-column: 2 / 3;
transform: none;

View File

@@ -18,21 +18,16 @@ export const iconPaths = {
'arrow-right': `<path fill="none" stroke-linecap="round" stroke-linejoin="round" stroke-width="16" d="M40 128h176m-72-72 72 72-72 72"/>`,
'arrow-left': `<path fill="none" stroke-linecap="round" stroke-linejoin="round" stroke-width="16" d="M216 128H40m72-72-72 72 72 72"/>`,
code: `<path fill="none" stroke-linecap="round" stroke-linejoin="round" stroke-width="16" d="m64 88-48 40 48 40m128-80 48 40-48 40M160 40 96 216"/>`,
'microphone-stage': `<circle cx="168" cy="88" r="64" fill="none" stroke-linecap="round" stroke-linejoin="round" stroke-width="16"/><path fill="none" stroke-linecap="round" stroke-linejoin="round" stroke-width="16" d="m213.3 133.3-90.6-90.6M100 156l-12 12m16.8-70.1L28.1 202.5a7.9 7.9 0 0 0 .8 10.4l14.2 14.2a7.9 7.9 0 0 0 10.4.8l104.6-76.7"/>`,
'hard-drives': `<path d="M208,136H48a16,16,0,0,0-16,16v48a16,16,0,0,0,16,16H208a16,16,0,0,0,16-16V152A16,16,0,0,0,208,136Zm0,64H48V152H208v48Zm0-160H48A16,16,0,0,0,32,56v48a16,16,0,0,0,16,16H208a16,16,0,0,0,16-16V56A16,16,0,0,0,208,40Zm0,64H48V56H208v48ZM192,80a12,12,0,1,1-12-12A12,12,0,0,1,192,80Zm0,96a12,12,0,1,1-12-12A12,12,0,0,1,192,176Z"/>`,
'cloud': `<path d="M160,40A88.09,88.09,0,0,0,81.29,88.67,64,64,0,1,0,72,216h88a88,88,0,0,0,0-176Zm0,160H72a48,48,0,0,1,0-96c1.1,0,2.2,0,3.29.11A88,88,0,0,0,72,128a8,8,0,0,0,16,0,72,72,0,1,1,72,72Z"/>`,
'network': '<path d="M232,112H136V88h8a16,16,0,0,0,16-16V40a16,16,0,0,0-16-16H112A16,16,0,0,0,96,40V72a16,16,0,0,0,16,16h8v24H24a8,8,0,0,0,0,16H56v32H48a16,16,0,0,0-16,16v32a16,16,0,0,0,16,16H80a16,16,0,0,0,16-16V176a16,16,0,0,0-16-16H72V128H184v32h-8a16,16,0,0,0-16,16v32a16,16,0,0,0,16,16h32a16,16,0,0,0,16-16V176a16,16,0,0,0-16-16h-8V128h32a8,8,0,0,0,0-16ZM112,40h32V72H112ZM80,208H48V176H80Zm128,0H176V176h32Z"/>',
'microphone-stage': `<circle cx="168" cy="88" r="64" fill="none" stroke-linecap="round" stroke-linejoin="round" stroke-width="16"/><path fill="none" stroke-linecap="round" stroke-linejoin="round" stroke-width="16" d="m213.3 133.3-90.6-90.6M100 156l-12 12m16.8-70.1L28.1 202.5a7.9 7.9 0 0 0 .8 10.4l14.2 14.2a7.9 7.9 0 0 0 10.4.8l104.6-76.7"/>`,
'pencil-line': `<path fill="none" stroke-linecap="round" stroke-linejoin="round" stroke-width="16" d="M96 216H48a8 8 0 0 1-8-8v-44.7a7.9 7.9 0 0 1 2.3-5.6l120-120a8 8 0 0 1 11.4 0l44.6 44.6a8 8 0 0 1 0 11.4Zm40-152 56 56"/><path fill="none" stroke-linecap="round" stroke-linejoin="round" stroke-width="16" d="M216 216H96l-55.5-55.5M164 92l-96 96"/>`,
'rocket-launch': `<path fill="none" stroke-linecap="round" stroke-linejoin="round" stroke-width="16" d="M94.1 184.6c-11.4 33.9-56.6 33.9-56.6 33.9s0-45.2 33.9-56.6m124.5-56.5L128 173.3 82.7 128l67.9-67.9C176.3 34.4 202 34.7 213 36.3a7.8 7.8 0 0 1 6.7 6.7c1.6 11 1.9 36.7-23.8 62.4Z"/><path fill="none" stroke-linecap="round" stroke-linejoin="round" stroke-width="16" d="M184.6 116.7v64.6a8 8 0 0 1-2.4 5.6l-32.3 32.4a8 8 0 0 1-13.5-4.1l-8.4-41.9m11.3-101.9H74.7a8 8 0 0 0-5.6 2.4l-32.4 32.3a8 8 0 0 0 4.1 13.5l41.9 8.4"/>`,
list: `<path stroke-linecap="round" stroke-linejoin="round" stroke-width="16" d="M40 128h176M40 64h176M40 192h176"/>`,
heart: `<path fill="none" stroke-linecap="round" stroke-linejoin="round" stroke-width="16" d="M128 216S28 160 28 92a52 52 0 0 1 100-20h0a52 52 0 0 1 100 20c0 68-100 124-100 124Z"/>`,
'moon-stars': `<path fill="none" stroke-linecap="round" stroke-linejoin="round" stroke-width="16" d="M216 112V64m24 24h-48m-24-64v32m16-16h-32m65 113A92 92 0 0 1 103 39h0a92 92 0 1 0 114 114Z"/>`,
sun: `<circle cx="128" cy="128" r="60" fill="none" stroke-linecap="round" stroke-linejoin="round" stroke-width="16"/><path fill="none" stroke-linecap="round" stroke-linejoin="round" stroke-width="16" d="M128 36V16M63 63 49 49m-13 79H16m47 65-14 14m79 13v20m65-47 14 14m13-79h20m-47-65 14-14"/>`,
'twitter-logo': `<path fill="none" stroke-linecap="round" stroke-linejoin="round" stroke-width="16" d="M128 88c0-22 18.5-40.3 40.5-40a40 40 0 0 1 36.2 24H240l-32.3 32.3A127.9 127.9 0 0 1 80 224c-32 0-40-12-40-12s32-12 48-36c0 0-64-32-48-120 0 0 40 40 88 48Z"/>`,
'codepen-logo': `<path fill="none" stroke-linecap="round" stroke-linejoin="round" stroke-width="16" d="m232 101-104 59-104-59 100.1-56.8a8.3 8.3 0 0 1 7.8 0Z"/><path fill="none" stroke-linecap="round" stroke-linejoin="round" stroke-width="16" d="m232 165-100.1 56.8a8.3 8.3 0 0 1-7.8 0L24 165l104-59Zm0-64v64M24 101v64m104-5v62.8m0-179.6V106"/>`,
'github-logo': `<g stroke-linecap="round" stroke-linejoin="round"><path fill="none" stroke-width="14.7" d="M55.7 167.2c13.9 1 21.3 13.1 22.2 14.6 4.2 7.2 10.4 9.6 18.3 7.1l1.1-3.4a60.3 60.3 0 0 1-25.8-11.9c-12-10.1-18-25.6-18-46.3"/><path fill="none" stroke-width="16" d="M61.4 205.1a24.5 24.5 0 0 1-3-6.1c-3.2-7.9-7.1-10.6-7.8-11.1l-1-.6c-2.4-1.6-9.5-6.5-7.2-13.9 1.4-4.5 6-7.2 12.3-7.2h.8c4 .3 7.6 1.5 10.7 3.2-9.1-10.1-13.6-24.3-13.6-42.3 0-11.3 3.5-21.7 10.1-30.4A46.7 46.7 0 0 1 65 67.3a8.3 8.3 0 0 1 5-4.7c2.8-.9 13.3-2.7 33.2 9.9a105 105 0 0 1 50.5 0c19.9-12.6 30.4-10.8 33.2-9.9 2.3.7 4.1 2.4 5 4.7 5 12.7 4 23.2 2.6 29.4 6.7 8.7 10 18.9 10 30.4 0 42.6-25.8 54.7-43.6 58.7 1.4 4.1 2.2 8.8 2.2 13.7l-.1 23.4v2.3"/><path fill="none" stroke-width="16" d="M160.9 185.7c1.4 4.1 2.2 8.8 2.2 13.7l-.1 23.4v2.3A98.6 98.6 0 1 0 61.4 205c-1.4-2.1-11.3-17.5-11.8-17.8-2.4-1.6-9.5-6.5-7.2-13.9 1.4-4.5 6-7.2 12.3-7.2h.8c4 .3 7.6 1.5 10.7 3.2-9.1-10.1-13.6-24.3-13.6-42.3 0-11.3 3.5-21.7 10.1-30.4A46.4 46.4 0 0 1 65 67.3a8.3 8.3 0 0 1 5-4.7c2.8-.9 13.3-2.7 33.2 9.9a105 105 0 0 1 50.5 0c19.9-12.6 30.4-10.8 33.2-9.9 2.3.7 4.1 2.4 5 4.7 5 12.7 4 23.2 2.6 29.4 6.7 8.7 10 18.9 10 30.4.1 42.6-25.8 54.7-43.6 58.6z"/><path fill="none" stroke-width="18.7" d="m170.1 203.3 17.3-12 17.2-18.7 9.5-26.6v-27.9l-9.5-27.5" /><path fill="none" stroke-width="22.7" d="m92.1 57.3 23.3-4.6 18.7-1.4 29.3 5.4m-110 32.6-8 16-4 21.4.6 20.3 3.4 13" /><path fill="none" stroke-width="13.3" d="M28.8 133a100 100 0 0 0 66.9 94.4v-8.7c-22.4 1.8-33-11.5-35.6-19.8-3.4-8.6-7.8-11.4-8.5-11.8"/></g>`,
'twitch-logo': `<path fill="none" stroke-linecap="round" stroke-linejoin="round" stroke-width="16" d="M165 200h-42a8 8 0 0 0-5 2l-46 38v-40H48a8 8 0 0 1-8-8V48a8 8 0 0 1 8-8h160a8 8 0 0 1 8 8v108a8 8 0 0 1-3 6l-43 36a8 8 0 0 1-5 2Zm3-112v48m-48-48v48"/>`,
'youtube-logo': `<path fill="none" stroke-linecap="round" stroke-linejoin="round" stroke-width="16" d="m160 128-48-32v64l48-32z"/><path fill="none" stroke-linecap="round" stroke-linejoin="round" stroke-width="16" d="M24 128c0 30 3 47 5 56a16 16 0 0 0 10 11c34 13 89 13 89 13s56 0 89-13a16 16 0 0 0 10-11c2-9 5-26 5-56s-3-47-5-56a16 16 0 0 0-10-11c-33-13-89-13-89-13s-55 0-89 13a16 16 0 0 0-10 11c-2 9-5 26-5 56Z"/>`,
'dribbble-logo': `<circle cx="128" cy="128" r="96" fill="none" stroke-linecap="round" stroke-linejoin="round" stroke-width="16"/><path fill="none" stroke-linecap="round" stroke-linejoin="round" stroke-width="16" d="M71 205a160 160 0 0 1 137-77l16 1m-36-76a160 160 0 0 1-124 59 165 165 0 0 1-30-3"/><path fill="none" stroke-linecap="round" stroke-linejoin="round" stroke-width="16" d="M86 42a161 161 0 0 1 74 177"/>`,
'discord-logo': `<circle stroke="none" cx="96" cy="144" r="12"/><circle stroke="none" cx="160" cy="144" r="12"/><path fill="none" stroke-linecap="round" stroke-linejoin="round" stroke-width="16" d="M74 80a175 175 0 0 1 54-8 175 175 0 0 1 54 8m0 96a175 175 0 0 1-54 8 175 175 0 0 1-54-8"/><path fill="none" stroke-linecap="round" stroke-linejoin="round" stroke-width="16" d="m155 182 12 24a8 8 0 0 0 9 4c25-6 46-16 61-30a8 8 0 0 0 3-8L206 59a8 8 0 0 0-5-5 176 176 0 0 0-30-9 8 8 0 0 0-9 5l-8 24m-53 108-12 24a8 8 0 0 1-9 4c-25-6-46-16-61-30a8 8 0 0 1-3-8L50 59a8 8 0 0 1 5-5 176 176 0 0 1 30-9 8 8 0 0 1 9 5l8 24"/>`,
'linkedin-logo': `<rect width="184" height="184" x="36" y="36" fill="none" stroke-linecap="round" stroke-linejoin="round" stroke-width="16" rx="8"/><path fill="none" stroke-linecap="round" stroke-linejoin="round" stroke-width="16" d="M120 112v64m-32-64v64m32-36a28 28 0 0 1 56 0v36"/><circle stroke="none" cx="88" cy="80" r="12"/>`,
'instagram-logo': `<circle cx="128" cy="128" r="40" fill="none" stroke-miterlimit="10" stroke-width="16"/><rect width="184" height="184" x="36" y="36" fill="none" stroke-linecap="round" stroke-linejoin="round" stroke-width="16" rx="48"/><circle cx="180" cy="76" r="12" stroke="none" />`,
'tiktok-logo': `<path fill="none" stroke-linecap="round" stroke-linejoin="round" stroke-width="16" d="M168 106a96 96 0 0 0 56 18V84a56 56 0 0 1-56-56h-40v128a28 28 0 1 1-40-25V89a68 68 0 1 0 80 67Z"/>`,
};

View File

@@ -1,14 +1,19 @@
---
import '../styles/global.css';
import directus from "../../lib/directus"
import { readSingleton } from "@directus/sdk";
interface Props {
title?: string | undefined;
description?: string | undefined;
}
const global = await directus.request(readSingleton("global"));
const {
title = 'Jeanine White: Personal Site',
description = 'The personal site of Jeanine White',
title = `${global.name}`,
description = `A profile of ${global.name}`,
} = Astro.props;
---
@@ -25,8 +30,8 @@ const {
href="https://fonts.googleapis.com/css2?family=Public+Sans:ital,wght@0,400;0,700;1,400&family=Rubik:wght@500;600&display=swap"
rel="stylesheet"
/>
<script is:inline>
// This code is inlined in the head to make dark mode instant & blocking.
const getThemePreference = () => {
if (typeof localStorage !== 'undefined' && localStorage.getItem('theme')) {
return localStorage.getItem('theme');
@@ -37,7 +42,6 @@ const {
document.documentElement.classList[isDark ? 'add' : 'remove']('theme-dark');
if (typeof localStorage !== 'undefined') {
// Watch the document element and persist user preference when it changes.
const observer = new MutationObserver(() => {
const isDark = document.documentElement.classList.contains('theme-dark');
localStorage.setItem('theme', isDark ? 'dark' : 'light');

View File

@@ -3,29 +3,28 @@ import Icon from './Icon.astro';
import ThemeToggle from './ThemeToggle.astro';
import type { iconPaths } from './IconPaths';
/** Main menu items */
import directus from "../../lib/directus"
import { readSingleton } from "@directus/sdk";
const textLinks: { label: string; href: string }[] = [
{ label: 'Home', href: '/' },
{ label: 'Work', href: '/work/' },
{ label: 'Projects', href: '/projects/' },
{ label: 'About', href: '/about/' },
];
/** Icon links to social media — edit these with links to your profiles! */
const iconLinks: { label: string; href: string; icon: keyof typeof iconPaths }[] = [
{ label: 'Twitter', href: 'https://twitter.com/me', icon: 'twitter-logo' },
{ label: 'Twitch', href: 'https://twitch.tv/me', icon: 'twitch-logo' },
{ label: 'GitHub', href: 'https://github.com/me', icon: 'github-logo' },
{ label: 'CodePen', href: 'https://codepen.io/me', icon: 'codepen-logo' },
{ label: 'dribbble', href: 'https://dribbble.com/me', icon: 'dribbble-logo' },
{ label: 'YouTube', href: 'https://www.youtube.com/@me/', icon: 'youtube-logo' },
{ label: 'GitHub', href: 'https://github.com/alexlebens', icon: 'github-logo' },
{ label: 'LinkedIn', href: 'https://www.linkedin.com/in/alexanderlebens', icon: 'linkedin-logo' },
];
const global = await directus.request(readSingleton("global"));
---
<nav>
<div class="menu-header">
<a href="/" class="site-title">
<Icon icon="terminal-window" color="var(--accent-regular)" size="1.6em" gradient />
Jeanine White
{global.name}
</a>
<menu-button>
<template>
@@ -121,26 +120,20 @@ const iconLinks: { label: string; href: string; icon: keyof typeof iconPaths }[]
constructor() {
super();
// Inject menu toggle button when JS runs.
this.appendChild(this.querySelector('template')!.content.cloneNode(true));
const btn = this.querySelector('button')!;
// Hide menu (shown by default to support no-JS browsers).
const menu = document.getElementById('menu-content')!;
menu.hidden = true;
// Add "menu-content" class in JS to avoid covering content in non-JS browsers.
menu.classList.add('menu-content');
/** Set whether the menu is currently expanded or collapsed. */
const setExpanded = (expand: boolean) => {
btn.setAttribute('aria-expanded', expand ? 'true' : 'false');
menu.hidden = !expand;
};
// Toggle menu visibility when the menu button is clicked.
btn.addEventListener('click', () => setExpanded(menu.hidden));
// Hide menu button for large screens.
const handleViewports = (e: MediaQueryList | MediaQueryListEvent) => {
setExpanded(e.matches);
btn.hidden = e.matches;

View File

@@ -1,16 +1,17 @@
---
import type { CollectionEntry } from 'astro:content';
import type { Post } from '../../lib/directus';
import { directus_url } from '../../lib/directus';
interface Props {
project: CollectionEntry<'work'>;
posts: Post;
}
const { data, slug } = Astro.props.project;
const post: Post = Astro.props.posts;
---
<a class="card" href={`/work/${slug}`}>
<span class="title">{data.title}</span>
<img src={data.img} alt={data.img_alt || ''} loading="lazy" decoding="async" />
<a class="card" href={`/projects/${post.slug}`}>
<span class="title">{post.title}</span>
<img src={`${directus_url}/assets/${post.image}?width=500`} alt={post.image_alt || ''} loading="lazy" decoding="async" />
</a>
<style>

View File

@@ -1,22 +1,27 @@
---
import Icon from './Icon.astro';
import directus from "../../lib/directus"
import { readSingleton } from "@directus/sdk";
const skills = await directus.request(readSingleton("skills"));
---
<section class="box skills">
<div class="stack gap-2 lg:gap-4">
<Icon icon="terminal-window" color="var(--accent-regular)" size="2.5rem" gradient />
<h2>Full Stack</h2>
<p>Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod.</p>
<Icon icon="cloud" color="var(--accent-regular)" size="2.5rem" gradient />
<h2 set:html={skills.skill_1}/>
<p set:html={skills.skill_1_description}/>
</div>
<div class="stack gap-2 lg:gap-4">
<Icon icon="trophy" color="var(--accent-regular)" size="2.5rem" gradient />
<h2>Industry Leader</h2>
<p>Neque viverra justo nec ultrices dui. Est ultricies integer quis auctor elit.</p>
<Icon icon="network" color="var(--accent-regular)" size="2.5rem" gradient />
<h2 set:html={skills.skill_2}/>
<p set:html={skills.skill_2_description}/>
</div>
<div class="stack gap-2 lg:gap-4">
<Icon icon="strategy" color="var(--accent-regular)" size="2.5rem" gradient />
<h2>Strategy-Minded</h2>
<p>Urna porttitor rhoncus dolor purus non enim praesent ornare.</p>
<h2 set:html={skills.skill_3}/>
<p set:html={skills.skill_3_description}/>
</div>
</section>

View File

@@ -74,16 +74,13 @@ import Icon from './Icon.astro';
const button = this.querySelector('button')!;
/** Set the theme to dark/light mode. */
const setTheme = (dark: boolean) => {
document.documentElement.classList[dark ? 'add' : 'remove']('theme-dark');
button.setAttribute('aria-pressed', String(dark));
};
// Toggle the theme when a user clicks the button.
button.addEventListener('click', () => setTheme(!this.isDark()));
// Initialize button state to reflect current theme.
setTheme(this.isDark());
}

View File

@@ -1,15 +0,0 @@
import { defineCollection, z } from 'astro:content';
export const collections = {
work: defineCollection({
type: 'content',
schema: z.object({
title: z.string(),
description: z.string(),
publishDate: z.coerce.date(),
tags: z.array(z.string()),
img: z.string(),
img_alt: z.string().optional(),
}),
}),
};

View File

@@ -1,23 +0,0 @@
---
title: Bloom Box
publishDate: 2019-12-01 00:00:00
img: /assets/stock-2.jpg
img_alt: A bright pink sheet of paper used to wrap flowers curves in front of rich blue background
description: |
We paired with a cutting-edge music API and a team of horticulturalists
to build AI-generated playlists that maximize houseplant health.
tags:
- Dev
- Branding
- Backend
---
Lorem ipsum dolor sit amet, consectetur adipiscing elit. Curabitur posuere commodo venenatis. Pellentesque habitant morbi tristique senectus et netus et malesuada fames ac turpis egestas. Nam non ligula vel metus efficitur hendrerit. In hac habitasse platea dictumst. Praesent et mauris ut mi dapibus semper. Curabitur tortor justo, efficitur sit amet pretium cursus, porta eget odio. Cras ac venenatis dolor. Donec laoreet posuere malesuada. Curabitur nec mi tempor, placerat leo sit amet, tincidunt est. Quisque pellentesque venenatis magna, eget tristique nibh pulvinar in. Vestibulum vitae volutpat arcu. Aenean ut malesuada odio, sit amet pellentesque odio. Suspendisse nunc elit, blandit nec hendrerit non, aliquet at magna. Donec id leo ut nulla sagittis sodales.
Integer vitae nibh elit. Suspendisse eget urna eu neque bibendum pharetra. Sed interdum lectus sem, in pulvinar magna dignissim vel. Quisque maximus at urna nec laoreet. Suspendisse potenti. Vestibulum rhoncus sem ut mi pellentesque, in vestibulum erat blandit. Aliquam sodales dui ac maximus consectetur. Duis quis est vehicula, imperdiet nisl nec, fermentum erat. Duis tortor diam, pharetra eu euismod in, vehicula non eros. Curabitur facilisis dui at erat ultrices gravida. In at nunc ultricies, pulvinar mi vel, sagittis mauris. Praesent pharetra posuere purus ac imperdiet. Nulla facilisi.
Sed pulvinar porttitor mi in ultricies. Etiam non dolor gravida eros pulvinar pellentesque et dictum ex. Proin eu ornare ligula, sed condimentum dui. Vivamus tincidunt tellus mi, sed semper ipsum pharetra a. Suspendisse sollicitudin at sapien nec volutpat. Etiam justo urna, laoreet ac lacus sed, ultricies facilisis dolor. Integer posuere, metus vel viverra gravida, risus elit ornare magna, id feugiat erat risus ullamcorper libero. Proin vitae diam auctor, laoreet lorem vitae, varius tellus.
Mauris sed eros in ex maximus volutpat. Suspendisse potenti. Donec lacinia justo consectetur sagittis tempor. Proin ullamcorper nisi vitae auctor rhoncus. Sed tristique aliquam augue. Pellentesque vitae fringilla ligula. Nulla arcu elit, efficitur eu nunc malesuada, eleifend tincidunt orci. Interdum et malesuada fames ac ante ipsum primis in faucibus. Integer mattis orci in bibendum ultricies. Quisque a dui erat. Phasellus et vulputate ipsum. Proin metus ex, lobortis nec ornare eget, bibendum ut sapien. Aliquam in dolor lobortis, aliquam tellus a, congue augue. Lorem ipsum dolor sit amet, consectetur adipiscing elit.
Aenean pretium purus augue, ut bibendum erat convallis quis. Cras condimentum quis velit ac mollis. Suspendisse non purus fringilla, venenatis nisl porta, finibus odio. Curabitur aliquet metus faucibus libero interdum euismod. Morbi sed magna nisl. Morbi odio nibh, facilisis vel sapien eu, tempus tincidunt erat. Nullam erat velit, sagittis at purus quis, tristique scelerisque tortor. Pellentesque lacinia tortor id est aliquam viverra. Vestibulum et diam ac ipsum mollis fringilla.

View File

@@ -1,22 +0,0 @@
---
title: h2.0
publishDate: 2019-10-02 00:00:00
img: /assets/stock-4.jpg
img_alt: Soft pink and baby blue water ripples together in a subtle texture.
description: |
We developed brand positioning and design assets for the launch
of a new colored water product.
tags:
- Design
- Branding
---
Lorem ipsum dolor sit amet, consectetur adipiscing elit. Curabitur posuere commodo venenatis. Pellentesque habitant morbi tristique senectus et netus et malesuada fames ac turpis egestas. Nam non ligula vel metus efficitur hendrerit. In hac habitasse platea dictumst. Praesent et mauris ut mi dapibus semper. Curabitur tortor justo, efficitur sit amet pretium cursus, porta eget odio. Cras ac venenatis dolor. Donec laoreet posuere malesuada. Curabitur nec mi tempor, placerat leo sit amet, tincidunt est. Quisque pellentesque venenatis magna, eget tristique nibh pulvinar in. Vestibulum vitae volutpat arcu. Aenean ut malesuada odio, sit amet pellentesque odio. Suspendisse nunc elit, blandit nec hendrerit non, aliquet at magna. Donec id leo ut nulla sagittis sodales.
Integer vitae nibh elit. Suspendisse eget urna eu neque bibendum pharetra. Sed interdum lectus sem, in pulvinar magna dignissim vel. Quisque maximus at urna nec laoreet. Suspendisse potenti. Vestibulum rhoncus sem ut mi pellentesque, in vestibulum erat blandit. Aliquam sodales dui ac maximus consectetur. Duis quis est vehicula, imperdiet nisl nec, fermentum erat. Duis tortor diam, pharetra eu euismod in, vehicula non eros. Curabitur facilisis dui at erat ultrices gravida. In at nunc ultricies, pulvinar mi vel, sagittis mauris. Praesent pharetra posuere purus ac imperdiet. Nulla facilisi.
Sed pulvinar porttitor mi in ultricies. Etiam non dolor gravida eros pulvinar pellentesque et dictum ex. Proin eu ornare ligula, sed condimentum dui. Vivamus tincidunt tellus mi, sed semper ipsum pharetra a. Suspendisse sollicitudin at sapien nec volutpat. Etiam justo urna, laoreet ac lacus sed, ultricies facilisis dolor. Integer posuere, metus vel viverra gravida, risus elit ornare magna, id feugiat erat risus ullamcorper libero. Proin vitae diam auctor, laoreet lorem vitae, varius tellus.
Mauris sed eros in ex maximus volutpat. Suspendisse potenti. Donec lacinia justo consectetur sagittis tempor. Proin ullamcorper nisi vitae auctor rhoncus. Sed tristique aliquam augue. Pellentesque vitae fringilla ligula. Nulla arcu elit, efficitur eu nunc malesuada, eleifend tincidunt orci. Interdum et malesuada fames ac ante ipsum primis in faucibus. Integer mattis orci in bibendum ultricies. Quisque a dui erat. Phasellus et vulputate ipsum. Proin metus ex, lobortis nec ornare eget, bibendum ut sapien. Aliquam in dolor lobortis, aliquam tellus a, congue augue. Lorem ipsum dolor sit amet, consectetur adipiscing elit.
Aenean pretium purus augue, ut bibendum erat convallis quis. Cras condimentum quis velit ac mollis. Suspendisse non purus fringilla, venenatis nisl porta, finibus odio. Curabitur aliquet metus faucibus libero interdum euismod. Morbi sed magna nisl. Morbi odio nibh, facilisis vel sapien eu, tempus tincidunt erat. Nullam erat velit, sagittis at purus quis, tristique scelerisque tortor. Pellentesque lacinia tortor id est aliquam viverra. Vestibulum et diam ac ipsum mollis fringilla.

View File

@@ -1,35 +0,0 @@
---
title: Markdown Mystery Tour
publishDate: 2020-03-02 00:00:00
img: /assets/stock-1.jpg
img_alt: Iridescent ripples of a bright blue and pink liquid
description: |
We designed a whodunnit-style game to introduce Markdown formatting. Suspense — suspicion — syntax!
tags:
- Design
- Dev
- User Testing
---
## Level-two heading
> Tell me and I forget. Teach me and I remember. Involve me and I learn.
Lorem ipsum dolor sit amet, <a href="https://astro.build/">Astro</a> makes people happy. Sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Proin nibh nisl condimentum id venenatis a condimentum vitae. Dapibus ultrices in iaculis nunc. Arcu odio ut sem nulla pharetra diam sit amet. Diam quis enim lobortis scelerisque fermentum dui faucibus in ornare.
Arcu dui vivamus arcu felis bibendum ut tristique et egestas. Eget gravida cum sociis natoque penatibus. Cras fermentum odio eu feugiat pretium nibh. Proin nibh nisl condimentum id venenatis. Porta nibh venenatis cras sed felis eget velit. Id diam vel quam elementum pulvinar etiam non.
### Level-three heading
Ultrices tincidunt arcu non sodales neque sodales ut. Sed enim ut sem viverra aliquet eget sit amet. Lacus luctus accumsan tortor posuere ac ut consequat semper viverra. Viverra accumsan in nisl nisi scelerisque eu ultrices. In massa tempor nec feugiat nisl pretium fusce.
### Level-three heading
Sed pulvinar porttitor mi in ultricies. Etiam non dolor gravida eros pulvinar pellentesque et dictum ex. Proin eu ornare ligula, sed condimentum dui. Vivamus tincidunt tellus mi, sed semper ipsum pharetra a. Suspendisse sollicitudin at sapien nec volutpat. Etiam justo urna, laoreet ac lacus sed, ultricies facilisis dolor. Integer posuere, metus vel viverra gravida, risus elit ornare magna, id feugiat erat risus ullamcorper libero. Proin vitae diam auctor, laoreet lorem vitae, varius tellus.
Aenean pretium purus augue, ut bibendum erat convallis quis. Cras condimentum quis velit ac mollis. Suspendisse non purus fringilla, venenatis nisl porta, finibus odio. Curabitur aliquet metus faucibus libero interdum euismod. Morbi sed magna nisl. Morbi odio nibh, facilisis vel sapien eu, tempus tincidunt erat. Nullam erat velit, sagittis at purus quis, tristique scelerisque tortor. Pellentesque lacinia tortor id est aliquam viverra. Vestibulum et diam ac ipsum mollis fringilla.
#### Level-four heading
- We noted this
- And also this other point

View File

@@ -1,22 +0,0 @@
---
title: Duvet Genius
publishDate: 2020-03-04 00:00:00
img: /assets/stock-3.jpg
img_alt: Pearls of silky soft white cotton, bubble up under vibrant lighting
description: |
We developed a virtual showcase for the softest bedding imaginable.
tags:
- Design
- Dev
- Branding
---
Lorem ipsum dolor sit amet, consectetur adipiscing elit. Curabitur posuere commodo venenatis. Pellentesque habitant morbi tristique senectus et netus et malesuada fames ac turpis egestas. Nam non ligula vel metus efficitur hendrerit. In hac habitasse platea dictumst. Praesent et mauris ut mi dapibus semper. Curabitur tortor justo, efficitur sit amet pretium cursus, porta eget odio. Cras ac venenatis dolor. Donec laoreet posuere malesuada. Curabitur nec mi tempor, placerat leo sit amet, tincidunt est. Quisque pellentesque venenatis magna, eget tristique nibh pulvinar in. Vestibulum vitae volutpat arcu. Aenean ut malesuada odio, sit amet pellentesque odio. Suspendisse nunc elit, blandit nec hendrerit non, aliquet at magna. Donec id leo ut nulla sagittis sodales.
Integer vitae nibh elit. Suspendisse eget urna eu neque bibendum pharetra. Sed interdum lectus sem, in pulvinar magna dignissim vel. Quisque maximus at urna nec laoreet. Suspendisse potenti. Vestibulum rhoncus sem ut mi pellentesque, in vestibulum erat blandit. Aliquam sodales dui ac maximus consectetur. Duis quis est vehicula, imperdiet nisl nec, fermentum erat. Duis tortor diam, pharetra eu euismod in, vehicula non eros. Curabitur facilisis dui at erat ultrices gravida. In at nunc ultricies, pulvinar mi vel, sagittis mauris. Praesent pharetra posuere purus ac imperdiet. Nulla facilisi.
Sed pulvinar porttitor mi in ultricies. Etiam non dolor gravida eros pulvinar pellentesque et dictum ex. Proin eu ornare ligula, sed condimentum dui. Vivamus tincidunt tellus mi, sed semper ipsum pharetra a. Suspendisse sollicitudin at sapien nec volutpat. Etiam justo urna, laoreet ac lacus sed, ultricies facilisis dolor. Integer posuere, metus vel viverra gravida, risus elit ornare magna, id feugiat erat risus ullamcorper libero. Proin vitae diam auctor, laoreet lorem vitae, varius tellus.
Mauris sed eros in ex maximus volutpat. Suspendisse potenti. Donec lacinia justo consectetur sagittis tempor. Proin ullamcorper nisi vitae auctor rhoncus. Sed tristique aliquam augue. Pellentesque vitae fringilla ligula. Nulla arcu elit, efficitur eu nunc malesuada, eleifend tincidunt orci. Interdum et malesuada fames ac ante ipsum primis in faucibus. Integer mattis orci in bibendum ultricies. Quisque a dui erat. Phasellus et vulputate ipsum. Proin metus ex, lobortis nec ornare eget, bibendum ut sapien. Aliquam in dolor lobortis, aliquam tellus a, congue augue. Lorem ipsum dolor sit amet, consectetur adipiscing elit.
Aenean pretium purus augue, ut bibendum erat convallis quis. Cras condimentum quis velit ac mollis. Suspendisse non purus fringilla, venenatis nisl porta, finibus odio. Curabitur aliquet metus faucibus libero interdum euismod. Morbi sed magna nisl. Morbi odio nibh, facilisis vel sapien eu, tempus tincidunt erat. Nullam erat velit, sagittis at purus quis, tristique scelerisque tortor. Pellentesque lacinia tortor id est aliquam viverra. Vestibulum et diam ac ipsum mollis fringilla.

View File

@@ -1,8 +1,4 @@
---
// Learn about using Astro layouts:
// https://docs.astro.build/en/core-concepts/layouts/
// Component Imports
import MainHead from '../components/MainHead.astro';
import Nav from '../components/Nav.astro';
import Footer from '../components/Footer.astro';
@@ -27,7 +23,6 @@ const { title, description } = Astro.props;
</div>
<script>
// Add “loaded” class once the document has completely loaded.
addEventListener('load', () => document.documentElement.classList.add('loaded'));
</script>
@@ -54,13 +49,12 @@ const { title, description } = Astro.props;
--bg-blend-mode: lighten;
}
/* These backgrounds are displayed below the fold, so we lazy load them
once the `.loaded` class has been set. */
:root.loaded {
--bg-image-subtle-1: url('/assets/backgrounds/bg-subtle-1-light-800w.jpg');
--bg-image-subtle-2: url('/assets/backgrounds/bg-subtle-2-light-800w.jpg');
--bg-image-footer: url('/assets/backgrounds/bg-footer-light-800w.jpg');
}
:root.loaded.theme-dark {
--bg-image-subtle-1: url('/assets/backgrounds/bg-subtle-1-dark-800w.jpg');
--bg-image-subtle-2: url('/assets/backgrounds/bg-subtle-2-dark-800w.jpg');
@@ -72,6 +66,7 @@ const { title, description } = Astro.props;
--bg-scale: 1;
--bg-image-main: url('/assets/backgrounds/bg-main-light-1440w.jpg');
}
:root.theme-dark {
--bg-image-main: url('/assets/backgrounds/bg-main-dark-1440w.jpg');
}
@@ -81,6 +76,7 @@ const { title, description } = Astro.props;
--bg-image-subtle-2: url('/assets/backgrounds/bg-subtle-2-light-1440w.jpg');
--bg-image-footer: url('/assets/backgrounds/bg-footer-light-1440w.jpg');
}
:root.loaded.theme-dark {
--bg-image-subtle-1: url('/assets/backgrounds/bg-subtle-1-dark-1440w.jpg');
--bg-image-subtle-2: url('/assets/backgrounds/bg-subtle-2-dark-1440w.jpg');
@@ -92,21 +88,20 @@ const { title, description } = Astro.props;
min-height: 100%;
isolation: isolate;
background:
/*noise*/
url('/assets/backgrounds/noise.png') top center/220px repeat,
/*footer*/ var(--bg-image-footer) bottom center/var(--bg-gradient-size) no-repeat,
/*header1*/ var(--bg-image-main-curves) top center/var(--bg-gradient-size) no-repeat,
/*header2*/ var(--bg-image-main) top center/var(--bg-gradient-size) no-repeat,
/*base*/ var(--gray-999);
background-blend-mode: /*noise*/
var(--bg-image-footer) bottom center/var(--bg-gradient-size) no-repeat,
var(--bg-image-main-curves) top center/var(--bg-gradient-size) no-repeat,
var(--bg-image-main) top center/var(--bg-gradient-size) no-repeat,
var(--gray-999);
background-blend-mode:
overlay,
/*footer*/ var(--bg-blend-mode),
/*header1*/ var(--bg-svg-blend-mode),
/*header2*/ normal,
/*base*/ normal;
var(--bg-blend-mode),
var(--bg-svg-blend-mode),
normal,
normal;
}
@media (forced-colors: active) {
/* Deactivate custom backgrounds for high contrast users. */
.backgrounds {
background: none;
background-blend-mode: none;

View File

@@ -3,9 +3,15 @@ import BaseLayout from '../layouts/BaseLayout.astro';
import ContactCTA from '../components/ContactCTA.astro';
import Hero from '../components/Hero.astro';
import directus, { directus_url } from "../../lib/directus"
import { readSingleton } from "@directus/sdk";
const global = await directus.request(readSingleton("global"));
const about = await directus.request(readSingleton("about"));
---
<BaseLayout title="About | Jeanine White" description="About Jeanine White Lorem Ipsum">
<BaseLayout title=`About | ${global.name}` description=`About ${global.name}`>
<div class="stack gap-20">
<main class="wrapper about">
<Hero
@@ -15,45 +21,38 @@ import Hero from '../components/Hero.astro';
<img
width="1553"
height="873"
src="/assets/at-work.jpg"
alt="Jeanine White at work with a colleague"
src=`${directus_url}/assets/${global.about}`
alt=`${global.name} hiking in Texas`
/>
</Hero>
<section>
<h2 class="section-title">Background</h2>
<div class="content">
<p>
Lorem ipsum dolor sit amet, <a href="https://astro.build/">Astro</a> makes people happy.
Sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Proin nibh nisl condimentum
id venenatis a condimentum vitae. Dapibus ultrices in iaculis nunc. Arcu odio ut sem nulla
pharetra diam sit amet. Diam quis enim lobortis scelerisque fermentum dui faucibus in ornare.
</p>
<p>
Arcu dui vivamus arcu felis bibendum ut tristique et egestas. Eget gravida cum sociis
natoque penatibus. Cras fermentum odio eu feugiat pretium nibh. Proin nibh nisl
condimentum id venenatis. Porta nibh venenatis cras sed felis eget velit. Id diam vel
quam elementum pulvinar etiam non.
</p>
<p>
Ultrices tincidunt arcu non sodales neque sodales ut. Sed enim ut sem viverra aliquet
eget sit amet. Lacus luctus accumsan tortor posuere ac ut consequat semper viverra.
Viverra accumsan in nisl nisi scelerisque eu ultrices. In massa tempor nec feugiat nisl
pretium fusce.
</p>
</div>
<div
class="content"
set:html={about.background}
/>
</section>
<section>
<h2 class="section-title">Experience</h2>
<div
class="content"
set:html={about.experience}
/>
</section>
<section>
<h2 class="section-title">Education</h2>
<div class="content">
<p>Corporis voluptates tenetur laudantium.</p>
</div>
<div
class="content"
set:html={about.education}
/>
</section>
<section>
<h2 class="section-title">Skills</h2>
<div class="content">
<p>officia unde omnis</p>
</div>
<h2 class="section-title">Certifications</h2>
<div
class="content"
set:html={about.certifications}
/>
</section>
</main>

View File

@@ -1,10 +1,6 @@
---
import { getCollection } from 'astro:content';
// Layout import — provides basic page elements: <head>, <nav>, <footer> etc.
import BaseLayout from '../layouts/BaseLayout.astro';
// Component Imports
import CallToAction from '../components/CallToAction.astro';
import Grid from '../components/Grid.astro';
import Hero from '../components/Hero.astro';
@@ -12,40 +8,46 @@ import Icon from '../components/Icon.astro';
import Pill from '../components/Pill.astro';
import PortfolioPreview from '../components/PortfolioPreview.astro';
// Page section components
import ContactCTA from '../components/ContactCTA.astro';
import Skills from '../components/Skills.astro';
// Content Fetching: List four most recent work projects
const projects = (await getCollection('work'))
.sort((a, b) => b.data.publishDate.valueOf() - a.data.publishDate.valueOf())
.slice(0, 4);
import directus, { directus_url } from "../../lib/directus"
import { readItems,readSingleton } from "@directus/sdk";
// Full Astro Component Syntax:
// https://docs.astro.build/basics/astro-components/
const global = await directus.request(readSingleton("global"));
const posts = await directus.request(
readItems("posts", {
fields: ['*'],
sort: ["-published_date"],
})
);
---
<BaseLayout>
<BaseLayout
title=`Home | ${global.name}`
description=""
>
<div class="stack gap-20 lg:gap-48">
<div class="wrapper stack gap-8 lg:gap-20">
<header class="hero">
<Hero
title="Hello, my name is Jeanine White"
tagline="I am a Creative Developer who is currently based in Portland, Oregon."
title=`Hello, my name is ${global.name}`
tagline={global.tagline}
align="start"
>
<div class="roles">
<Pill><Icon icon="hard-drives" size="1.33em" /> Engineer</Pill>
<Pill><Icon icon="code" size="1.33em" /> Developer</Pill>
<Pill><Icon icon="microphone-stage" size="1.33em" /> Speaker</Pill>
<Pill><Icon icon="pencil-line" size="1.33em" /> Writer</Pill>
</div>
</Hero>
<img
alt="Jeanine White smiling in a red plaid shirt and tortoise shell glasses"
alt=`${global.name} in Antarctica`
width="480"
height="620"
src="/assets/portrait.jpg"
src=`${directus_url}/assets/${global.portrait}`
/>
</header>
@@ -55,53 +57,31 @@ const projects = (await getCollection('work'))
<main class="wrapper stack gap-20 lg:gap-48">
<section class="section with-background with-cta">
<header class="section-header stack gap-2 lg:gap-4">
<h3>Selected Work</h3>
<p>Take a look below at some of my featured work for clients from the past few years.</p>
<h3>Selected Projects</h3>
<p>Take a look below at some of my projects from the past few years.</p>
</header>
<div class="gallery">
<Grid variant="offset">
{
projects.map((project) => (
<li>
<PortfolioPreview project={project} />
</li>
))
}
{
posts.map((post) => (
<li>
<PortfolioPreview posts={post} />
</li>
))
}
</Grid>
</div>
<div class="cta">
<CallToAction href="/work/">
<CallToAction href="/projects/">
View All
<Icon icon="arrow-right" size="1.2em" />
</CallToAction>
</div>
</section>
<section class="section with-background bg-variant">
<header class="section-header stack gap-2 lg:gap-4">
<h3>Mentions</h3>
<p>
I have been fortunate enough to receive praise for my work in several publications. Take
a look below to learn more.
</p>
</header>
<div class="gallery">
<Grid variant="small">
{
['Medium', 'BuzzFeed', 'The Next Web', 'awwwards.', 'TechCrunch'].map((brand) => (
<li class="mention-card">
<p>{brand}</p>
</li>
))
}
</Grid>
</div>
</section>
</main>
<ContactCTA />
</div>
</BaseLayout>
@@ -147,8 +127,6 @@ const projects = (await getCollection('work'))
}
}
/* ====================================================== */
.section {
display: grid;
gap: 2rem;
@@ -228,8 +206,6 @@ const projects = (await getCollection('work'))
}
}
/* ====================================================== */
.mention-card {
display: flex;
height: 7rem;

45
src/pages/projects.astro Normal file
View File

@@ -0,0 +1,45 @@
---
import BaseLayout from '../layouts/BaseLayout.astro';
import ContactCTA from '../components/ContactCTA.astro';
import PortfolioPreview from '../components/PortfolioPreview.astro';
import Hero from '../components/Hero.astro';
import Grid from '../components/Grid.astro';
import directus from "../../lib/directus"
import { readItems,readSingleton } from "@directus/sdk";
const global = await directus.request(readSingleton("global"));
const posts = await directus.request(
readItems("posts", {
fields: ['*'],
sort: ["-published_date"],
})
);
---
<BaseLayout
title=`My Projects | ${global.name}`
description=`Learn about ${global.name}'s most recent projects`
>
<div class="stack gap-20">
<main class="wrapper stack gap-8">
<Hero
title="My Projects"
tagline="See my most recent projects below to get an idea of my past experience."
align="start"
/>
<Grid variant="offset">
{
posts.map((post) => (
<li>
<PortfolioPreview posts={post} />
</li>
))
}
</Grid>
</main>
<ContactCTA />
</div>
</BaseLayout>

View File

@@ -1,6 +1,4 @@
---
import { type CollectionEntry, getCollection } from 'astro:content';
import BaseLayout from '../../layouts/BaseLayout.astro';
import ContactCTA from '../../components/ContactCTA.astro';
@@ -8,46 +6,44 @@ import Hero from '../../components/Hero.astro';
import Icon from '../../components/Icon.astro';
import Pill from '../../components/Pill.astro';
interface Props {
entry: CollectionEntry<'work'>;
}
import directus, { directus_url } from "../../../lib/directus";
import { readItems } from "@directus/sdk";
// This is a dynamic route that generates a page for every Markdown file in src/content/
// Read more about dynamic routes and this `getStaticPaths` function in the Astro docs:
// https://docs.astro.build/en/core-concepts/routing/#dynamic-routes
export async function getStaticPaths() {
const work = await getCollection('work');
return work.map((entry) => ({
params: { slug: entry.slug },
props: { entry },
}));
const posts = await directus.request(readItems("posts", {
fields: ['*'],
}));
return posts.map((post) => ({ params: { slug: post.slug }, props: post }));
}
const { entry } = Astro.props;
const { Content } = await entry.render();
const post = Astro.props;
const published_date: string = new Date(post.published_date).toLocaleDateString();
---
<BaseLayout title={entry.data.title} description={entry.data.description}>
<BaseLayout title={post.title}>
<div class="stack gap-20">
<div class="stack gap-15">
<header>
<div class="wrapper stack gap-2">
<a class="back-link" href="/work/"><Icon icon="arrow-left" /> Work</a>
<Hero title={entry.data.title} align="start">
<a class="back-link" href="/projects/"><Icon icon="arrow-left" /> Projects</a>
<Hero
title={post.title}
tagline=`Published on ${published_date}`
align="start"
>
<div class="details">
<div class="tags">
{entry.data.tags.map((t) => <Pill>{t}</Pill>)}
{post.tags.map((t) => <Pill>{t}</Pill>)}
</div>
<p class="description">{entry.data.description}</p>
</div>
</Hero>
</div>
</header>
<main class="wrapper">
<div class="stack gap-10 content">
{entry.data.img && <img src={entry.data.img} alt={entry.data.img_alt || ''} />}
{post.image && <img src={`${directus_url}/assets/${post.image}?width=500`} alt={post.image_alt || ''} />}
<div class="content">
<Content />
<div set:html={post.content} />
</div>
</div>
</main>

View File

@@ -1,39 +0,0 @@
---
import { getCollection } from 'astro:content';
import BaseLayout from '../layouts/BaseLayout.astro';
import ContactCTA from '../components/ContactCTA.astro';
import PortfolioPreview from '../components/PortfolioPreview.astro';
import Hero from '../components/Hero.astro';
import Grid from '../components/Grid.astro';
const projects = (await getCollection('work')).sort(
(a, b) => b.data.publishDate.valueOf() - a.data.publishDate.valueOf(),
);
---
<BaseLayout
title="My Work | Jeanine White"
description="Learn about Jeanine White's most recent projects"
>
<div class="stack gap-20">
<main class="wrapper stack gap-8">
<Hero
title="My Work"
tagline="See my most recent projects below to get an idea of my past experience."
align="start"
/>
<Grid variant="offset">
{
projects.map((project) => (
<li>
<PortfolioPreview project={project} />
</li>
))
}
</Grid>
</main>
<ContactCTA />
</div>
</BaseLayout>

View File

@@ -1,6 +1,4 @@
/* Global variables */
:root {
/* Colors */
--gray-0: #090b11;
--gray-50: #141925;
--gray-100: #283044;
@@ -25,7 +23,6 @@
--link-color: var(--accent-regular);
/* Gradients */
--gradient-stop-1: var(--accent-light);
--gradient-stop-2: var(--accent-regular);
--gradient-stop-3: var(--accent-dark);
@@ -44,7 +41,6 @@
);
--gradient-stroke: linear-gradient(180deg, var(--gray-900), var(--gray-700));
/* Shadows */
--shadow-sm: 0px 6px 3px rgba(9, 11, 17, 0.01), 0px 4px 2px rgba(9, 11, 17, 0.01),
0px 2px 2px rgba(9, 11, 17, 0.02), 0px 0px 1px rgba(9, 11, 17, 0.03);
--shadow-md: 0px 28px 11px rgba(9, 11, 17, 0.01), 0px 16px 10px rgba(9, 11, 17, 0.03),
@@ -52,7 +48,6 @@
--shadow-lg: 0px 62px 25px rgba(9, 11, 17, 0.01), 0px 35px 21px rgba(9, 11, 17, 0.05),
0px 16px 16px rgba(9, 11, 17, 0.1), 0px 4px 9px rgba(9, 11, 17, 0.12);
/* Text Sizes */
--text-sm: 0.875rem;
--text-base: 1rem;
--text-md: 1.125rem;
@@ -63,13 +58,11 @@
--text-4xl: 3.5rem;
--text-5xl: 4.5rem;
/* Fonts */
--font-system: system-ui, -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Oxygen, Ubuntu,
Cantarell, 'Open Sans', 'Helvetica Neue', sans-serif;
--font-body: 'Public Sans', var(--font-system);
--font-brand: Rubik, var(--font-system);
/* Transitions */
--theme-transition: 0.2s ease-in-out;
}
@@ -176,8 +169,6 @@ h5 {
font-size: var(--text-xl);
}
/* Utilities */
.sr-only {
position: absolute;
width: 1px;

View File

@@ -1,3 +1,5 @@
{
"extends": "astro/tsconfigs/strict"
}
"extends": "astro/tsconfigs/strict",
"include": [".astro/types.d.ts", "**/*"],
"exclude": ["dist"]
}