Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
11 changes: 11 additions & 0 deletions .claude/launch.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
{
"version": "0.0.1",
"configurations": [
{
"name": "dev",
"runtimeExecutable": "bun",
"runtimeArgs": ["run", "dev"],
"port": 5173
}
]
}
131 changes: 131 additions & 0 deletions .claude/skills/commit/SKILL.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,131 @@
---
name: commit
description: Use this always making a commit. Creates git commits following conventional commit standards
context: fork
disable-model-invocation: false
allowed-tools:
- Read
- Bash(cd:*)
- Bash(git status:*)
- Bash(git diff:*)
- Bash(git add:*)
- Bash(git stash:*)
- Bash(git commit:*)
---

# Git Commit

Create a git commit following the [Conventional Commits](https://www.conventionalcommits.org/en/v1.0.0/) specification.

## Critical Rules

1. **Do not modify any files** - diffs may differ from when last read
2. **No AI attribution** - no `Co-Authored-By`, no "generated by AI", no mention of Claude or any AI
3. **If files are already staged** - commit them directly, do not stage/unstage
4. **Stop after committing** - do not continue with additional work
5. **Verify code style** - read `CODE_STYLE.md` and check that staged changes follow the project's coding conventions. Flag any violations to the user before committing.

## Format

```text
<type>(<scope>): <description>

[optional body]
```

- **type**: Category of change (required)
- **scope**: Project name in this monorepo (optional - omit for root-level changes)
- **description**: Short summary in imperative mood, lowercase, no period (max 50 chars, truncated at 72)
- **body**: Only if essential context can't fit in subject; use bullet points for key details

## Types

| Type | Description |
| ---------- | ---------------------------- |
| `feat` | New feature |
| `fix` | Bug fix |
| `refactor` | Code change without fix/feat |
| `docs` | Documentation only |
| `test` | Adding or updating tests |
| `chore` | Maintenance, deps, configs |
| `perf` | Performance improvement |
| `style` | Formatting, whitespace |

## Examples

```text
feat: add contract work section with booking link
feat: add light/dark/system theme toggle
fix: prevent theme flash on first paint
fix: stop header nav colliding with wordmark below md
refactor: extract theme logic into useTheme composable
chore: bump vite to v7
perf: serve headshot as optimized jpeg
docs: update readme with bun commands
style: reduce card rounding across sections
```

## Granular Commits

Each commit should contain one logical change. Create separate commits for:

- **Package vs usages**: Change to a crate/package in one commit, update consumers in another
- **Unrelated changes in same scope**: Two bug fixes in the same project = two commits
- **Cross-scope changes**: Changes spanning multiple projects = one commit per project

### Staging Strategies

**Partial file staging with `git add -p`:** When a file contains multiple unrelated changes (e.g., a barrel export with two new exports), stage only the hunks for the current commit.

**Stash approach for complex cases:** If partial staging is too complex:

1. `git stash push -p` to stash unrelated changes
2. Commit the remaining changes
3. `git stash pop` and commit the next logical change

### Examples

**Stage together:**

- New component `ContractSection.vue` + its import and usage in `App.vue`
- A copy change in `data.ts` + the matching markup tweak in the section component that renders it

**Stage separately:**

- Two new components `StackSection.vue` and `EducationSection.vue`, each with their own `App.vue` wiring
- A `useTheme.ts` composable change + an unrelated style fix in `style.css`

## Instructions

1. If not already in the repo root, `cd` into it first (do NOT use `git -C`, it bypasses allowed-tools)
2. Run `git status` to check current state
3. If files are already staged:
- Run `git diff --staged` to review staged changes
- Commit directly
4. If nothing staged:
- Run `git diff` to see unstaged changes
- Help decide what to stage together (see Granular Commits above)
- Stage with `git add <file>` or `git add -p <file>` for partial staging
- Commit

### Commit Syntax

For simple commits (subject only):

```bash
git commit -m "type(scope): description"
```

For commits with a body (rare, only when essential):

```bash
git commit -m "$(cat <<'EOF'
type(scope): description

- essential detail that doesn't fit in subject
- another key point if needed
EOF
)"
```

$ARGUMENTS
25 changes: 25 additions & 0 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
name: CI

on:
push:
branches: [main]
pull_request:

jobs:
build:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v7

- uses: oven-sh/setup-bun@v2
with:
bun-version: 1.3.14

- name: Install dependencies
run: bun install --frozen-lockfile

- name: Lint and check formatting
run: bunx biome ci .

- name: Type-check and build
run: bun run build
4 changes: 2 additions & 2 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -11,10 +11,10 @@ node_modules
dist
dist-ssr
*.local
.claude/settings.local.json

# Editor directories and files
.vscode/*
!.vscode/extensions.json
.vscode
.idea
.DS_Store
*.suo
Expand Down
3 changes: 0 additions & 3 deletions .vscode/extensions.json

This file was deleted.

70 changes: 70 additions & 0 deletions CODE_STYLE.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,70 @@
# Code Style

## Formatting

Biome: tabs (width 4), double quotes, semicolons, trailing commas, 120 char width. No `any`, no unused vars/imports, no non-null assertions. Vue SFCs relax the unused/undeclared rules. `bun run lint` to check, `bun run format` to fix.

### Blank Lines

Blank line after multi-line block (3+ lines) when followed by another statement. Single-line pairs fine. Single line then multi-line fine. Only multi-line then next statement needs the blank line.

```typescript
// Good
watchEffect(() => {
localStorage.setItem("theme", theme.value);
document.documentElement.classList.toggle("dark", isDark.value);
});

export function useTheme() { ... }

// Good - single lines together
const media = window.matchMedia("(prefers-color-scheme: dark)");
const systemDark = ref(media.matches);
```

## Comments

Concise, simple, as-needed. Every function gets a JSDoc block comment (`/** */`) concisely describing what it does. Avoid redundant inline comments that restate the code.

**Punctuation:** No em-dashes, en-dashes, or semicolons in comments. Prefer starting a new sentence. Comments do not end in a period. Use periods only to separate multiple sentences on the same line, and the final sentence still gets no trailing period.

```typescript
// Good - JSDoc function comment, no trailing period
/**
* Flips to the opposite of whatever is currently showing
*/
const toggle = () => { ... };

// Bad - em-dash and trailing period
// Flips the theme — system resolves first.
```

## Dependencies

Prefer popular, well-maintained packages over hand-rolling functionality for anything with a standard. Avoid general-purpose utility packages like `lodash` to keep bundle size in check; import only focused, single-purpose packages.

## Vue / Frontend

**Component Organization:** One component per section in `src/components/`. Small, one-time-use markup can stay inline in its parent. Larger or reusable pieces get their own file.

**Content vs markup:** All copy, links, and profile data live in `src/data.ts`. Components render data, they do not embed prose.

**Icons:** Inline SVG only. No emojis or unicode symbols as icons. Terminal ASCII art (tree glyphs, interpuncts) is content, not iconography.

## Typography

| Font | Class | Usage |
| ------------------- | -------------- | --------------------------------------------------------- |
| Bricolage Grotesque | `font-display` | Headings, titles (`font-semibold` to `font-extrabold`) |
| Instrument Sans | `font-sans` | Body, UI (default, `font-normal` to `font-medium`) |
| JetBrains Mono | `font-mono` | Labels, terminal, meta (`font-normal` to `font-semibold`) |

## Theming

Hex colors in CSS vars, defined in `src/style.css` (`:root` for light, `.dark` overrides) and exposed to Tailwind via `@theme inline`. Light/dark via `.dark` class on `<html>`, applied pre-paint by the inline script in `index.html`. Rust-orange accent (`--c-accent`), warm paper light theme, deep ink dark theme. The stack terminal stays dark in both themes.

Semantic tokens: `bg`, `surface`, `ink` (text), `soft` (muted text), `line` (borders), `accent`, `accent-soft`. Use these, never raw hex in components.

## Motion

Load-in stagger via `.rise` (hero only), scroll reveal via the `v-reveal` directive. All animation respects `prefers-reduced-motion`.
10 changes: 9 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
@@ -1 +1,9 @@
# t3ned.dev
# gmiles.dev

Personal portfolio site built with Vue 3, Tailwind CSS v4, Vite, and TypeScript on [Bun](https://bun.sh).

```sh
bun install
bun run dev
bun run build
```
Loading