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
File renamed without changes.
3 changes: 3 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -27,3 +27,6 @@ playwright-report/
*.njsproj
*.sln
*.sw?

# Claude
.claude/settings.local.json
42 changes: 42 additions & 0 deletions CLAUDE.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
# CLAUDE.md

This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository.

## Project Overview

Client-side password generator PWA built with Vue 3 + Vite. Deployed at passwords.roga.dev via Vercel. Fully offline-capable — no backend, no server-side logic. Uses `crypto.getRandomValues()` for cryptographically secure password generation.

## Commands

```bash
pnpm dev # Start dev server (localhost:5173)
pnpm build # Production build
pnpm test # Unit tests (jsdom via vitest)
pnpm test:watch # Unit tests in watch mode
pnpm test:browser # Browser tests (Playwright-backed vitest)
pnpm test:all # Unit + browser tests
pnpm test:e2e # Playwright end-to-end tests
pnpm test:e2e:ui # Playwright E2E with interactive UI
```

Run a single test file: `pnpm vitest run tests/unit/urlParams.test.js`

## Architecture

- **State management**: Reactive store via `src/stores/settingsStore.js` (Vue `reactive()` composable, not Vuex/Pinia). Single source of truth consumed by all components via `useSettings()`.
- **Password generation**: Pure function in `src/utils/password.js` — takes options object, returns password string or `"Error: ..."` string on failure. Error strings are checked with `startsWith('Error:')` in the UI.
- **URL params**: `src/utils/urlParams.js` handles bidirectional sync between settings and URL query string (`?len=24&exUpper&exSym`). Boolean params use presence-means-true convention. Settings load from URL on mount, and URL updates on every setting change via `history.replaceState`.
- **Component hierarchy**: `App.vue` → `PasswordGenerator.vue` (orchestrator) → `OptionsPanel.vue`, `KeyboardExcluder.vue`, `NetworkMonitor.vue`

## Testing

Three test tiers with separate configs:
- **Unit tests** (`tests/unit/`): `vitest.config.js`, jsdom environment
- **Browser tests** (`tests/browser/`): `vitest.browser.config.js`, real Chromium via Playwright
- **E2E tests** (`tests/e2e/`): `playwright.config.js`, runs against dev server (auto-started locally, provided externally in CI)

CI runs Chromium only. Locally, E2E runs Chromium + Firefox + WebKit.

## Styling

Tailwind CSS v4 with PostCSS. Global styles in `src/main.css`, component-scoped styles via `<style scoped>`. Dark theme (zinc-950 background) with emerald accent color.
7 changes: 3 additions & 4 deletions index.html
Original file line number Diff line number Diff line change
Expand Up @@ -34,10 +34,9 @@
<meta property="twitter:description" content="Generate strong, secure passwords instantly. Works completely offline - your passwords never leave your device." />
<meta property="twitter:image" content="https://passwords.roga.dev/images/og-image.jpg" />

<!-- Fonts: Geist for UI, JetBrains Mono for passwords -->
<link rel="preconnect" href="https://fonts.googleapis.com">
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
<link href="https://fonts.googleapis.com/css2?family=Geist:wght@400;500;600;700&family=JetBrains+Mono:wght@400;500;600&display=swap" rel="stylesheet">
<!-- Self-hosted fonts: Geist for UI, JetBrains Mono for passwords -->
<link rel="preload" href="/fonts/geist-latin-wght-normal.woff2" as="font" type="font/woff2" crossorigin>
<link rel="preload" href="/fonts/jetbrains-mono-latin-wght-normal.woff2" as="font" type="font/woff2" crossorigin>
</head>
<body class="bg-zinc-950 text-zinc-100 antialiased">
<div id="app"></div>
Expand Down
18 changes: 17 additions & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -38,8 +38,24 @@
},
"pnpm": {
"onlyBuiltDependencies": [
"esbuild",
"sharp"
]
],
"overrides": {
"lodash@>=4.0.0 <=4.17.22": ">=4.17.23",
"@isaacs/brace-expansion@<=5.0.0": ">=5.0.1",
"minimatch@>=5.0.0 <5.1.8": ">=5.1.8",
"minimatch@>=9.0.0 <9.0.7": ">=9.0.7 <10.0.0",
"minimatch@>=10.0.0 <10.2.3": ">=10.2.3",
"rollup@<2.80.0": ">=2.80.0",
"rollup@>=4.0.0 <4.59.0": ">=4.59.0",
"serialize-javascript@<7.0.5": ">=7.0.5",
"ajv@>=7.0.0-alpha.0 <8.18.0": ">=8.18.0",
"happy-dom@<20.8.9": ">=20.8.9",
"brace-expansion@>=2.0.0 <2.0.3": ">=2.0.3",
"picomatch@<2.3.2": ">=2.3.2",
"picomatch@>=4.0.0 <4.0.4": ">=4.0.4"
}
},
"packageManager": "pnpm@10.28.0+sha512.05df71d1421f21399e053fde567cea34d446fa02c76571441bfc1c7956e98e363088982d940465fd34480d4d90a0668bc12362f8aa88000a64e83d0b0e47be48"
}
Loading
Loading