git-history-ui 3.2.0 → 3.2.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +29 -0
- package/README.md +151 -127
- package/build/frontend/chunk-RPBKHRPI.js +2 -0
- package/build/frontend/index.html +2 -2
- package/build/frontend/main-6GA6B4NK.js +1 -0
- package/build/frontend/styles-AH3HC64Q.css +1 -0
- package/dist/backend/cache/sqliteIndex.d.ts +3 -1
- package/dist/backend/cache/sqliteIndex.js +35 -6
- package/dist/backend/cache/sqliteIndex.js.map +1 -1
- package/dist/backend/gitService.d.ts +21 -0
- package/dist/backend/gitService.js +112 -0
- package/dist/backend/gitService.js.map +1 -1
- package/dist/backend/insights.js +37 -9
- package/dist/backend/insights.js.map +1 -1
- package/dist/backend/server.d.ts +3 -1
- package/dist/backend/server.js +4 -2
- package/dist/backend/server.js.map +1 -1
- package/dist/cli.js +11 -7
- package/dist/cli.js.map +1 -1
- package/package.json +3 -1
- package/build/frontend/chunk-NDC3FSO4.js +0 -2
- package/build/frontend/main-AW2YOC32.js +0 -1
- package/build/frontend/styles-BOEVKAI2.css +0 -1
package/CHANGELOG.md
CHANGED
|
@@ -4,6 +4,35 @@ All notable changes to this project are documented in this file.
|
|
|
4
4
|
The format follows [Keep a Changelog](https://keepachangelog.com/en/1.1.0/) and
|
|
5
5
|
this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
|
|
6
6
|
|
|
7
|
+
## [3.2.2] - 2026-05-02
|
|
8
|
+
|
|
9
|
+
### Changed
|
|
10
|
+
|
|
11
|
+
- Hardened large-repo performance: insights now use a single `git log --numstat`
|
|
12
|
+
pass, SQLite indexing streams git output instead of buffering full logs, and
|
|
13
|
+
the commit graph keeps its canvas viewport-sized so it remains smooth beyond
|
|
14
|
+
browser canvas-height limits.
|
|
15
|
+
|
|
16
|
+
### Fixed
|
|
17
|
+
|
|
18
|
+
- Preserved rename semantics in churn calculations, safely rejected streaming
|
|
19
|
+
callback failures, and protected streamed index builds from UTF-8 chunk
|
|
20
|
+
boundary corruption.
|
|
21
|
+
|
|
22
|
+
## [3.2.1] - 2026-05-02
|
|
23
|
+
|
|
24
|
+
### Fixed
|
|
25
|
+
|
|
26
|
+
- **`npx git-history-ui` no longer prints help and exits.** When the
|
|
27
|
+
`presets` subcommand was added in v3.2.0, the root commander program
|
|
28
|
+
was left without a default `.action()`. Commander v12 reacts to that
|
|
29
|
+
by printing help and exiting whenever the user invokes the binary
|
|
30
|
+
without a subcommand. A no-args invocation now correctly starts the
|
|
31
|
+
server, matching pre-v3.2.0 behavior.
|
|
32
|
+
- Added a CLI smoke test (`src/__tests__/cli.test.ts`) that runs the
|
|
33
|
+
built binary with `--help`, `--version`, and no args so this kind of
|
|
34
|
+
regression can't ship silently again.
|
|
35
|
+
|
|
7
36
|
## [3.2.0] - 2026-05-02
|
|
8
37
|
|
|
9
38
|
The "Distribution & scale" release. This phase makes the tool faster on big
|
package/README.md
CHANGED
|
@@ -5,136 +5,175 @@
|
|
|
5
5
|
[](https://www.npmjs.com/package/git-history-ui)
|
|
6
6
|
[](https://bundlephobia.com/result?p=git-history-ui)
|
|
7
7
|
[](https://github.com/beingmartinbmc/git-history-ui)
|
|
8
|
-
[](https://github.com/beingmartinbmc/git-history-ui/issues)
|
|
9
8
|
|
|
10
|
-
**Git Intelligence in your browser.**
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
9
|
+
**Git Intelligence in your browser.**
|
|
10
|
+
|
|
11
|
+
Turn your git history into something you can actually understand:
|
|
12
|
+
|
|
13
|
+
- 🔎 Ask questions in plain English
|
|
14
|
+
- 📦 See commits grouped by feature or PR
|
|
15
|
+
- 🕰️ Travel through time and diff any state
|
|
16
|
+
- 🎯 Understand impact, not just changes
|
|
17
|
+
|
|
18
|
+
Zero setup. Runs locally. Your code never leaves your machine unless you opt in.
|
|
19
|
+
|
|
20
|
+
```bash
|
|
21
|
+
npx git-history-ui@latest
|
|
22
|
+
```
|
|
23
|
+
|
|
24
|
+
## ⚡ 10-second workflow
|
|
25
|
+
|
|
26
|
+
1. Run `npx git-history-ui` inside any git repo
|
|
27
|
+
2. Search: *"login bug last month"*
|
|
28
|
+
3. Jump to the commit
|
|
29
|
+
4. Inspect the diff and what it impacted
|
|
30
|
+
|
|
31
|
+
Done.
|
|
15
32
|
|
|
16
33
|
## 👀 Preview
|
|
17
34
|
|
|
18
35
|

|
|
19
36
|
|
|
37
|
+
> A demo GIF showing NL search, the timeline slider, and grouped view is on
|
|
38
|
+
> the way. In the meantime, `npx git-history-ui@latest` is the fastest way
|
|
39
|
+
> to see it for yourself — it opens in your browser in under a second.
|
|
40
|
+
|
|
41
|
+
## 🤔 Why this exists
|
|
42
|
+
|
|
43
|
+
Git history is hard to understand:
|
|
44
|
+
|
|
45
|
+
- commits are flat
|
|
46
|
+
- context is missing
|
|
47
|
+
- debugging across branches is painful
|
|
48
|
+
- GitHub's UI hides your local and unpushed work
|
|
49
|
+
|
|
50
|
+
`git-history-ui` turns that history into something **searchable, grouped,
|
|
51
|
+
explorable, and explainable** — without a desktop install or a cloud
|
|
52
|
+
account.
|
|
53
|
+
|
|
54
|
+
## ✨ What makes it different
|
|
55
|
+
|
|
56
|
+
Four things you don't get from `git log`, GitHub, or most desktop clients:
|
|
57
|
+
|
|
58
|
+
- **Natural-language search.** "login bug last month", "payments by alice".
|
|
59
|
+
A heuristic intent parser handles dates, authors, and keyword synonyms;
|
|
60
|
+
optional Anthropic / OpenAI key adds semantic re-ranking on top.
|
|
61
|
+
- **PR & feature grouping.** Switch the commit list to *Grouped* mode to
|
|
62
|
+
see commits clustered by pull request or Conventional Commits scope.
|
|
63
|
+
- **Time-travel timeline.** A horizontal slider that scrubs the repo state
|
|
64
|
+
at any point in time and live-diffs it against HEAD.
|
|
65
|
+
- **Commit impact analysis.** One click reveals which files, modules, and
|
|
66
|
+
related commits a change actually touches — not just the diff.
|
|
67
|
+
|
|
68
|
+
## 🤝 AI is optional, opt-in, and on your key
|
|
69
|
+
|
|
70
|
+
- Heuristic mode works out of the box, no key required.
|
|
71
|
+
- Set `ANTHROPIC_API_KEY` or `OPENAI_API_KEY` to upgrade NL search ranking
|
|
72
|
+
and unlock "Explain change" / "Summarize diff" actions.
|
|
73
|
+
- Prompts run from your machine to your provider. Your repo, your key,
|
|
74
|
+
your call.
|
|
75
|
+
|
|
20
76
|
## 🚀 Quick Start
|
|
21
77
|
|
|
22
78
|
```bash
|
|
23
|
-
# Go to the git repository you want to inspect
|
|
24
79
|
cd /path/to/your/project
|
|
25
|
-
|
|
26
|
-
# Run directly with npx (no installation needed)
|
|
27
80
|
npx git-history-ui@latest
|
|
28
81
|
```
|
|
29
82
|
|
|
30
|
-
That's it
|
|
31
|
-
It reads history from the current working
|
|
83
|
+
That's it. The app starts on `http://localhost:3000` and opens your
|
|
84
|
+
browser automatically. It reads history from the current working
|
|
85
|
+
directory — no installs, no config, no account.
|
|
32
86
|
|
|
33
|
-
|
|
87
|
+
## ⚖️ How it compares
|
|
34
88
|
|
|
35
|
-
|
|
89
|
+
- **vs GitHub UI:** NL search and PR grouping work *with* your unpushed
|
|
90
|
+
commits. Time travel and impact analysis aren't on GitHub at all.
|
|
91
|
+
- **vs `tig` / `git log`:** visual lanes, browser diffs, optional AI
|
|
92
|
+
explanations, insights dashboard.
|
|
93
|
+
- **vs desktop clients (GitKraken, SourceTree, Fork):** starts on demand,
|
|
94
|
+
no project import, no account, no native install. AI features are
|
|
95
|
+
pay-as-you-go on *your* key — nothing about your code leaves your
|
|
96
|
+
machine unless you opt in.
|
|
36
97
|
|
|
37
|
-
|
|
38
|
-
- GitHub's commit UI does not show your local or unpushed commits.
|
|
39
|
-
- Desktop clients can be heavy when you just want a quick read on one repo.
|
|
40
|
-
- `git-history-ui` gives you a fast, local, visual way to explore history from any git repository.
|
|
98
|
+
## 📦 All features
|
|
41
99
|
|
|
42
|
-
|
|
100
|
+
<details>
|
|
101
|
+
<summary><strong>Click to expand the full feature list</strong></summary>
|
|
43
102
|
|
|
44
|
-
|
|
45
|
-
repos get an FTS5-backed index in `~/.git-history-ui/`. Falls back to
|
|
46
|
-
git-shelling silently if the native module isn't available.
|
|
47
|
-
Endpoints: `GET /api/index/stats`, `POST /api/index/build`.
|
|
48
|
-
- **Streaming commits** — `GET /api/commits/stream` (SSE) progressively
|
|
49
|
-
pushes commits as `git log` produces them.
|
|
50
|
-
- **Virtualized commit graph** — The canvas only paints rows currently on
|
|
51
|
-
screen, so 50k-commit histories scroll without dropping frames.
|
|
52
|
-
- **Shareable URLs** — `POST /api/share` returns a deep link with view-state
|
|
53
|
-
encoded in the query string (no relay server needed for the common case).
|
|
54
|
-
- **CLI presets** — `--preset <name>` / `--save-preset <name>` and
|
|
55
|
-
`git-history-ui presets list|delete`, stored in
|
|
56
|
-
`~/.git-history-ui/presets.json`.
|
|
57
|
-
- **Embeds** — Chrome extension scaffold (`apps/chrome-extension/`) and
|
|
58
|
-
GitHub App scaffold (`apps/github-app/`) that add a "View in
|
|
59
|
-
git-history-ui" button to GitHub PR / commit pages.
|
|
60
|
-
|
|
61
|
-
## ✨ What's new in v3 — "Git Intelligence"
|
|
62
|
-
|
|
63
|
-
- **Natural-language search** — Ask "login bug last month" or "payments by alice".
|
|
64
|
-
A built-in heuristic intent parser extracts dates, authors, and keyword
|
|
65
|
-
synonyms; if you set `ANTHROPIC_API_KEY` or `OPENAI_API_KEY`, it adds
|
|
66
|
-
semantic re-ranking on top.
|
|
67
|
-
- **PR & feature grouping** — Switch the commit list to "Grouped" mode to see
|
|
68
|
-
commits clustered by pull request (GitHub merge & squash patterns) or
|
|
69
|
-
Conventional Commits scope (`feat(auth):`, `fix(payments):`). Optional
|
|
70
|
-
GitHub PR enrichment when `GITHUB_TOKEN` is set.
|
|
71
|
-
- **Time travel** — A horizontal timeline slider that shows the repo state
|
|
72
|
-
(HEAD, branches, tags) at any point and computes a live diff vs HEAD.
|
|
73
|
-
- **File history & blame** — Click any file in a commit's Files panel to see
|
|
74
|
-
every commit that touched it, with a tabbed blame view powered by
|
|
75
|
-
`highlight.js`.
|
|
76
|
-
- **Commit impact analysis** — One click reveals files touched, modules
|
|
77
|
-
affected, dependency ripple (parsed from JS/TS imports), and other commits
|
|
78
|
-
that touched the same files.
|
|
79
|
-
- **Insights dashboard** — Top contributors, hotspots, churn over time, and
|
|
80
|
-
a heuristic risky-files score for code reviewers and tech leads.
|
|
81
|
-
- **AI extras (optional)** — "Explain this change" on commits and "Summarize"
|
|
82
|
-
on diffs, both gated on a configured API key.
|
|
83
|
-
- **Local-first annotations** — Add notes to commits stored at
|
|
84
|
-
`~/.git-history-ui/<repo>/annotations.json`.
|
|
103
|
+
### Exploration
|
|
85
104
|
|
|
86
|
-
|
|
105
|
+
- **Canvas commit graph** with branch lanes, ref pills, hover/selected
|
|
106
|
+
states; viewport-virtualized so 50k-commit histories stay smooth.
|
|
107
|
+
- **Real-time filtering** by author, date, text, file path.
|
|
108
|
+
- **Unified & split diffs** with `highlight.js`, collapse-unchanged
|
|
109
|
+
blocks, side-by-side scroll-sync, and intra-line word highlighting.
|
|
110
|
+
- **Dark / light / system theme** with single-click toggle.
|
|
87
111
|
|
|
88
|
-
|
|
89
|
-
- **Real-time filtering** by author, date, text, file path
|
|
90
|
-
- **Unified & split diffs** with `highlight.js`, plus collapse-unchanged blocks
|
|
91
|
-
- **Dark / light / system theme** with single-click toggle
|
|
92
|
-
- **Zero setup** — `npx git-history-ui@latest`, that's it
|
|
112
|
+
### Code understanding
|
|
93
113
|
|
|
94
|
-
|
|
114
|
+
- **File-level history.** Click any file in a commit to see every commit
|
|
115
|
+
that touched it.
|
|
116
|
+
- **Blame view** powered by `highlight.js`, tabbed inside file history.
|
|
117
|
+
- **Insights dashboard.** Top contributors, hotspots (treemap), churn
|
|
118
|
+
over time (d3 area chart), heuristic risky-files score.
|
|
119
|
+
- **Commit impact card.** Files touched, modules affected, dependency
|
|
120
|
+
ripple parsed from JS/TS imports, related commits — including a d3
|
|
121
|
+
force-directed graph view.
|
|
95
122
|
|
|
96
|
-
|
|
97
|
-
commits, and time travel + impact analysis aren't on GitHub at all.
|
|
98
|
-
- **vs `tig` or `git log`**: visual lanes, browser diffs, AI explanations,
|
|
99
|
-
insights dashboard.
|
|
100
|
-
- **vs desktop clients (GitKraken, SourceTree, Fork)**: starts on demand with
|
|
101
|
-
no project import, no account, no native install. AI features are
|
|
102
|
-
pay-as-you-go on *your* key — nothing about your code leaves your machine
|
|
103
|
-
unless you opt in.
|
|
123
|
+
### Collaboration
|
|
104
124
|
|
|
105
|
-
|
|
125
|
+
- **Local-first annotations.** Per-commit comment threads stored in
|
|
126
|
+
`~/.git-history-ui/<repo>/annotations.json`.
|
|
127
|
+
- **Shareable URLs.** `POST /api/share` returns a deep link with the
|
|
128
|
+
current view-state encoded in the query string — no relay server
|
|
129
|
+
required for the common case.
|
|
130
|
+
- **"Explain this change"** AI card on the commit detail panel (opt-in).
|
|
106
131
|
|
|
107
|
-
###
|
|
132
|
+
### Performance & scale
|
|
108
133
|
|
|
109
|
-
|
|
134
|
+
- **SQLite indexer (optional).** Install `better-sqlite3` and large
|
|
135
|
+
repos get an FTS5-backed index in `~/.git-history-ui/`. Silent
|
|
136
|
+
fallback to git-shelling when the native module isn't available.
|
|
137
|
+
Endpoints: `GET /api/index/stats`, `POST /api/index/build`.
|
|
138
|
+
- **Streaming commits.** `GET /api/commits/stream` (SSE) pushes commits
|
|
139
|
+
as `git log` produces them.
|
|
140
|
+
- **Virtualized commit graph.** Only the visible viewport is painted;
|
|
141
|
+
scrolling is `requestAnimationFrame`-throttled.
|
|
110
142
|
|
|
111
|
-
|
|
112
|
-
# Custom port
|
|
113
|
-
npx git-history-ui@latest --port 8080
|
|
143
|
+
### CLI
|
|
114
144
|
|
|
115
|
-
|
|
116
|
-
|
|
145
|
+
- **Presets.** `--preset <name>` / `--save-preset <name>` and a
|
|
146
|
+
`git-history-ui presets list|delete` subcommand, stored in
|
|
147
|
+
`~/.git-history-ui/presets.json`.
|
|
148
|
+
- **Standard filters.** `--file`, `--author`, `--since`, `--port`,
|
|
149
|
+
`--no-open`, `--cwd`, `--llm <provider>`.
|
|
117
150
|
|
|
118
|
-
|
|
119
|
-
npx git-history-ui@latest --author "your-name"
|
|
151
|
+
### Embeds (experimental scaffolds)
|
|
120
152
|
|
|
121
|
-
|
|
122
|
-
|
|
153
|
+
- **Chrome extension** (`apps/chrome-extension/`) injects a "View in
|
|
154
|
+
git-history-ui" button on github.com PR / commit pages.
|
|
155
|
+
- **GitHub App** (`apps/github-app/`) scaffold for the same deep-link
|
|
156
|
+
strategy at the org level.
|
|
123
157
|
|
|
124
|
-
|
|
125
|
-
npx git-history-ui@latest --no-open
|
|
158
|
+
See [`CHANGELOG.md`](./CHANGELOG.md) for per-version detail.
|
|
126
159
|
|
|
127
|
-
|
|
128
|
-
|
|
160
|
+
</details>
|
|
161
|
+
|
|
162
|
+
## 📖 Usage
|
|
163
|
+
|
|
164
|
+
Run from inside the git repository you want to inspect.
|
|
165
|
+
|
|
166
|
+
```bash
|
|
167
|
+
npx git-history-ui@latest --port 8080 # custom port
|
|
168
|
+
npx git-history-ui@latest --file src/app.js # filter by file
|
|
169
|
+
npx git-history-ui@latest --author "alice" # filter by author
|
|
170
|
+
npx git-history-ui@latest --since 2024-01-01 # filter by date
|
|
171
|
+
npx git-history-ui@latest --no-open # don't open the browser
|
|
172
|
+
npx git-history-ui@latest --help # full flag list
|
|
129
173
|
```
|
|
130
174
|
|
|
131
175
|
### Optional: bring your own AI key
|
|
132
176
|
|
|
133
|
-
Natural-language search and "Explain change" / "Summarize diff" actions all
|
|
134
|
-
work without an API key (heuristic mode). Set one of these to upgrade them
|
|
135
|
-
with a real model — your code never leaves the host running git-history-ui
|
|
136
|
-
except for the prompt you explicitly trigger:
|
|
137
|
-
|
|
138
177
|
```bash
|
|
139
178
|
# Anthropic (recommended; uses claude-3-5-haiku by default)
|
|
140
179
|
export ANTHROPIC_API_KEY=sk-ant-...
|
|
@@ -143,65 +182,46 @@ export ANTHROPIC_API_KEY=sk-ant-...
|
|
|
143
182
|
export OPENAI_API_KEY=sk-...
|
|
144
183
|
|
|
145
184
|
# Force a specific provider when both are set
|
|
146
|
-
export GHUI_LLM_PROVIDER=anthropic #
|
|
147
|
-
|
|
148
|
-
npx git-history-ui@latest
|
|
185
|
+
export GHUI_LLM_PROVIDER=anthropic # anthropic | openai | heuristic
|
|
149
186
|
```
|
|
150
187
|
|
|
151
188
|
### Optional: GitHub PR enrichment
|
|
152
189
|
|
|
153
|
-
Set `GITHUB_TOKEN` (a fine-grained PAT with read access to your repo) to
|
|
154
|
-
hydrate the grouped view with PR titles, authors, and labels:
|
|
155
|
-
|
|
156
190
|
```bash
|
|
157
|
-
export GITHUB_TOKEN=ghp_...
|
|
158
|
-
npx git-history-ui@latest
|
|
191
|
+
export GITHUB_TOKEN=ghp_... # fine-grained PAT, read-only on the repo
|
|
159
192
|
```
|
|
160
193
|
|
|
194
|
+
This hydrates the *Grouped* view with PR titles, authors, and labels.
|
|
195
|
+
|
|
161
196
|
## 🏭 Production
|
|
162
197
|
|
|
163
|
-
### Build for Production
|
|
164
198
|
```bash
|
|
165
|
-
#
|
|
166
|
-
npm run
|
|
167
|
-
|
|
168
|
-
# Start production server
|
|
169
|
-
npm run start:production
|
|
199
|
+
npm run build:production # build backend + frontend
|
|
200
|
+
npm run start:production # start the production server
|
|
170
201
|
```
|
|
171
202
|
|
|
172
203
|
### Docker
|
|
204
|
+
|
|
173
205
|
```bash
|
|
174
|
-
# Build and run with Docker
|
|
175
206
|
docker build -t git-history-ui .
|
|
176
207
|
docker run -p 3000:3000 git-history-ui
|
|
177
208
|
```
|
|
178
209
|
|
|
179
210
|
## 🛠️ Development
|
|
180
211
|
|
|
181
|
-
### Setup
|
|
182
212
|
```bash
|
|
183
|
-
# Clone and install
|
|
184
213
|
git clone https://github.com/beingmartinbmc/git-history-ui.git
|
|
185
214
|
cd git-history-ui
|
|
186
215
|
npm install
|
|
187
|
-
|
|
188
|
-
#
|
|
189
|
-
npm run dev
|
|
190
|
-
```
|
|
191
|
-
|
|
192
|
-
### Testing
|
|
193
|
-
```bash
|
|
194
|
-
# Run backend tests
|
|
195
|
-
npm test
|
|
196
|
-
|
|
197
|
-
# Run frontend tests
|
|
216
|
+
npm run dev # runs backend + frontend with hot reload
|
|
217
|
+
npm test # backend tests
|
|
198
218
|
cd frontend && npm test
|
|
199
219
|
```
|
|
200
220
|
|
|
201
221
|
## 📋 Requirements
|
|
202
222
|
|
|
203
|
-
- **Node.js**: 20.19.0 or
|
|
204
|
-
- **Git**:
|
|
223
|
+
- **Node.js**: 20.19.0+ or 22.12.0+
|
|
224
|
+
- **Git**: any version (must be in a git repository)
|
|
205
225
|
|
|
206
226
|
## 🤝 Contributing
|
|
207
227
|
|
|
@@ -213,8 +233,12 @@ cd frontend && npm test
|
|
|
213
233
|
|
|
214
234
|
## 📄 License
|
|
215
235
|
|
|
216
|
-
MIT
|
|
236
|
+
MIT — see [LICENSE](LICENSE).
|
|
217
237
|
|
|
218
238
|
---
|
|
219
239
|
|
|
220
|
-
|
|
240
|
+
## ⭐ If this saved you time
|
|
241
|
+
|
|
242
|
+
[Star the repo](https://github.com/beingmartinbmc/git-history-ui) — it
|
|
243
|
+
helps more developers discover it, and it tells me which features to
|
|
244
|
+
double down on.
|
|
@@ -0,0 +1,2 @@
|
|
|
1
|
+
import{a as Xt,b as Jt,c as mn}from"./chunk-36NFLS3P.js";import{a as nn}from"./chunk-R33W2FKN.js";import{a as Zt,b as Qt,c as qt,h as Kt}from"./chunk-YSTG766K.js";import{a as en}from"./chunk-NUMLL3OZ.js";import{a as G}from"./chunk-N7UHDKJ7.js";import{e as on,f as rn,g as an,h as sn,i as ln,j as cn,k as dn}from"./chunk-QUDEGJKI.js";import{d as Yt}from"./chunk-3FFYILBL.js";import{a as tn}from"./chunk-ITIFFECZ.js";import{$ as f,$a as Tt,Ab as _,B as ht,Bb as B,C as Me,Cb as Ne,D as _t,Db as Bt,Ea as Pe,Fb as tt,Ga as s,Gb as nt,Hb as it,I as vt,Ia as Dt,Ja as Je,Jb as ue,Ka as kt,Lb as he,Ma as Pt,Mb as _e,N as Ct,Ob as Ve,P as xt,Pa as D,Q as Xe,Qa as pe,R as Oe,Ra as oe,Rb as jt,S as Ee,Sa as et,Sb as ee,Ta as v,Tb as j,V as bt,Va as Rt,W as V,Wa as fe,Wb as Gt,X as de,Xa as It,Xb as Ht,Z as Q,Zb as $t,ab as ge,db as u,dc as U,e as pt,ea as M,eb as l,ec as I,fa as O,fb as a,fc as Fe,g as Ke,ga as wt,gb as b,hb as Nt,hc as T,i as ft,ib as Vt,j as N,ja as yt,jb as Ft,ka as De,kb as Re,la as St,lb as Ie,lc as Wt,m as gt,mb as F,mc as Ut,n as ut,nb as S,nc as ze,oa as x,ob as C,pb as zt,q as W,qa as Mt,qb as Lt,ra as Ot,s as Se,sa as ke,sb as q,tb as K,ub as X,va as me,vb as Te,wb as J,xb as z,yb as At,za as Et,zb as c}from"./chunk-TQE5NWMZ.js";var Le=class i{http=f(ze);base="/api";list(n){return this.http.get(`${this.base}/annotations/${n}`)}add(n,e,t){return this.http.post(`${this.base}/annotations/${n}`,{author:e,body:t})}remove(n,e){return this.http.delete(`${this.base}/annotations/${n}/${e}`)}static \u0275fac=function(e){return new(e||i)};static \u0275prov=V({token:i,factory:i.\u0275fac,providedIn:"root"})};var Mn=["svg"];function On(i,n){i&1&&(l(0,"div",8),c(1,"No graph data \u2014 changed files have no detectable internal imports."),a())}var Ae=class i{impact=null;svgRef;simulation=null;hasData=!1;ngAfterViewInit(){this.render()}ngOnChanges(){this.render()}ngOnDestroy(){this.simulation?.stop()}render(){if(!this.svgRef)return;let n=this.svgRef.nativeElement,e=on(n);e.selectAll("*").remove();let t=this.impact;if(!t||t.dependencyRipple.length===0&&t.modules.length===0){this.hasData=!1;return}this.hasData=!0;let o=n.clientWidth||600,r=280,m=new Map,h=(p,H,se)=>{let P=m.get(p);return P||(P={id:p,group:H,label:se},m.set(p,P)),P};for(let p of t.files)h(`f:${p}`,"changed",ot(p));for(let p of t.modules)h(`m:${p}`,"module",p);for(let p of t.dependencyRipple)h(`f:${p.from}`,"changed",ot(p.from)),h(`f:${p.to}`,"imported",ot(p.to));let g=[];for(let p of t.dependencyRipple)g.push({source:`f:${p.from}`,target:`f:${p.to}`,type:"imports"});for(let p of t.files){let H=En(p);t.modules.includes(H)&&g.push({source:`f:${p}`,target:`m:${H}`,type:"in-module"})}let d=Array.from(m.values()),w=e.append("g").attr("stroke","var(--border-strong)").attr("stroke-opacity",.5).selectAll("line").data(g).join("line").attr("stroke-dasharray",p=>p.type==="in-module"?"2,3":null),R=e.append("g").selectAll("circle").data(d).join("circle").attr("r",p=>p.group==="module"?7:5).attr("fill",p=>p.group==="changed"?"var(--accent)":p.group==="imported"?"#f59e0b":"#8b5cf6").attr("stroke","var(--bg-app)").attr("stroke-width",1.5).call(ye());R.append("title").text(p=>p.id.slice(2));let Y=e.append("g").selectAll("text").data(d).join("text").attr("class","node-label").attr("dx",8).attr("dy",3).text(p=>p.label);this.simulation?.stop(),this.simulation=cn(d).force("link",ln(g).id(p=>p.id).distance(60).strength(.4)).force("charge",dn().strength(-160)).force("center",an(o/2,r/2)).force("collide",sn(14)).on("tick",()=>{w.attr("x1",p=>p.source.x??0).attr("y1",p=>p.source.y??0).attr("x2",p=>p.target.x??0).attr("y2",p=>p.target.y??0),R.attr("cx",p=>p.x??0).attr("cy",p=>p.y??0),Y.attr("x",p=>p.x??0).attr("y",p=>p.y??0)});function ye(){function p(P,E){P.active||window.__impactSim?.alphaTarget?.(.3).restart(),E.fx=E.x,E.fy=E.y}function H(P,E){E.fx=P.x,E.fy=P.y}function se(P,E){P.active||window.__impactSim?.alphaTarget?.(0),E.fx=null,E.fy=null}return rn().on("start",p).on("drag",H).on("end",se)}window.__impactSim=this.simulation}static \u0275fac=function(e){return new(e||i)};static \u0275cmp=D({type:i,selectors:[["app-impact-graph"]],viewQuery:function(e,t){if(e&1&&q(Mn,7),e&2){let o;K(o=X())&&(t.svgRef=o.first)}},inputs:{impact:"impact"},features:[ke],decls:11,vars:1,consts:[["svg",""],[1,"legend"],[1,"dot","dot-changed"],[1,"dot","dot-imported"],[1,"dot","dot-module"],[1,"canvas-wrap"],["width","100%","height","280","aria-label","Commit impact graph"],["class","empty",4,"ngIf"],[1,"empty"]],template:function(e,t){e&1&&(l(0,"div",1),b(1,"span",2),c(2," changed "),b(3,"span",3),c(4," imports "),b(5,"span",4),c(6," module "),a(),l(7,"div",5),wt(),b(8,"svg",6,0),v(10,On,2,0,"div",7),a()),e&2&&(s(10),u("ngIf",!t.hasData))},dependencies:[T,I],styles:["[_nghost-%COMP%]{display:block}.legend[_ngcontent-%COMP%]{display:flex;gap:.75rem;align-items:center;font-size:11px;color:var(--fg-muted);margin-bottom:.4rem}.dot[_ngcontent-%COMP%]{display:inline-block;width:8px;height:8px;border-radius:50%;margin-right:4px}.dot-changed[_ngcontent-%COMP%]{background:var(--accent)}.dot-imported[_ngcontent-%COMP%]{background:#f59e0b}.dot-module[_ngcontent-%COMP%]{background:#8b5cf6}.canvas-wrap[_ngcontent-%COMP%]{position:relative;background:var(--bg-app);border-radius:var(--radius-sm);border:1px solid var(--border-soft);overflow:hidden}.empty[_ngcontent-%COMP%]{position:absolute;inset:0;display:grid;place-items:center;color:var(--fg-muted);font-size:11px;pointer-events:none}svg[_ngcontent-%COMP%] [_ngcontent-%COMP%]:global(.node-label){font-size:9px;fill:var(--fg-secondary);font-family:var(--font-mono, monospace);pointer-events:none}"],changeDetection:0})};function ot(i){let n=i.split("/");return n[n.length-1]}function En(i){let n=i.split("/");return n.length===1?"(root)":n.slice(0,Math.min(n.length-1,3)).join("/")}function Dn(i,n){if(i&1&&(l(0,"span",36),c(1),a()),i&2){let e=n.$implicit;s(),_(e)}}function kn(i,n){if(i&1&&(l(0,"span",37),c(1),a()),i&2){let e=n.$implicit;s(),_(e)}}function Pn(i,n){i&1&&(l(0,"span",38),c(1,"merge"),a())}function Rn(i,n){if(i&1&&(l(0,"pre",39),c(1),a()),i&2){let e=C().ngIf;s(),_(e.body)}}function In(i,n){if(i&1){let e=F();l(0,"div",40)(1,"span",41),c(2,"AI"),a(),l(3,"span",42),c(4),a(),l(5,"button",43),S("click",function(){M(e);let o=C(2);return O(o.explanation.set(null))}),c(6,"\xD7"),a()()}if(i&2){let e=n.ngIf;s(4),_(e)}}function Tn(i,n){if(i&1&&(l(0,"div",44),c(1),a()),i&2){let e=n.ngIf;s(),_(e)}}function Nn(i,n){if(i&1&&(l(0,"li"),c(1),a()),i&2){let e=n.$implicit;s(),_(e)}}function Vn(i,n){if(i&1){let e=F();l(0,"li",28),S("click",function(){let o=M(e).$implicit,r=C(3);return O(r.state.selectHash(o.hash))}),l(1,"code"),c(2),a(),l(3,"span"),c(4),a()()}if(i&2){let e=n.$implicit;s(2),_(e.hash.slice(0,7)),s(2),_(e.subject)}}function Fn(i,n){if(i&1&&(l(0,"div",45)(1,"div",46)(2,"span"),c(3,"Impact"),a(),l(4,"span",47),c(5),a()(),b(6,"app-impact-graph",48),l(7,"div",49)(8,"div")(9,"h4"),c(10,"Modules"),a(),l(11,"ul",50),v(12,Nn,2,1,"li",51),a()(),l(13,"div")(14,"h4"),c(15,"Related commits"),a(),l(16,"ul",52),v(17,Vn,5,2,"li",53),a()()()()),i&2){let e=n.ngIf;s(5),Bt(" ",e.files.length," files \xB7 ",e.modules.length," modules \xB7 ",e.relatedCommits.length," related commits "),s(),u("impact",e),s(6),u("ngForOf",e.modules),s(5),u("ngForOf",e.relatedCommits)}}function zn(i,n){if(i&1&&(l(0,"span",54),c(1),a()),i&2){let e=C(2);s(),_(e.files().length)}}function Ln(i,n){if(i&1&&(l(0,"span",63),c(1),a()),i&2){let e=C().$implicit;s(),B("+",e.additions)}}function An(i,n){if(i&1&&(l(0,"span",64),c(1),a()),i&2){let e=C().$implicit;s(),B("\u2212",e.deletions)}}function Bn(i,n){if(i&1){let e=F();l(0,"div",55)(1,"button",56),S("click",function(){let o=M(e).$implicit,r=C(2);return O(r.selectFile(o))}),b(2,"span",57),l(3,"span",58),c(4),a(),l(5,"span",59),v(6,Ln,2,1,"span",60)(7,An,2,1,"span",61),a()(),l(8,"button",62),S("click",function(){let o=M(e).$implicit,r=C(2);return O(r.openFileHistory(o.file))}),c(9," \u23F1 "),a()()}if(i&2){let e,t=n.$implicit,o=C(2);s(),z("selected",t.file===((e=o.activeFile())==null?null:e.file)),s(),ge("data-status",t.status),s(),u("title",t.file),s(),_(t.file),s(2),u("ngIf",t.additions),s(),u("ngIf",t.deletions)}}function jn(i,n){i&1&&(l(0,"div",65),c(1," No files changed. "),a())}function Gn(i,n){i&1&&(l(0,"div",65),c(1,"Loading\u2026"),a())}function Hn(i,n){if(i&1){let e=F();l(0,"div",66)(1,"div",67)(2,"strong"),c(3),a(),l(4,"span",68),c(5),he(6,"date"),a(),l(7,"button",69),S("click",function(){let o=M(e).$implicit,r=C(2);return O(r.deleteComment(o.id))}),c(8,"\xD7"),a()(),l(9,"p",70),c(10),a()()}if(i&2){let e=n.$implicit;s(3),_(e.author),s(2),_(_e(6,3,e.createdAt,"short")),s(5),_(e.body)}}function $n(i,n){if(i&1){let e=F();Re(0),l(1,"header",2)(2,"div",3)(3,"span",4),c(4),a(),l(5,"span",5),v(6,Dn,2,1,"span",6)(7,kn,2,1,"span",7)(8,Pn,2,0,"span",8),a()(),l(9,"h2",9),c(10),a(),l(11,"div",10)(12,"span"),c(13),a(),l(14,"span",11),c(15,"\u2022"),a(),l(16,"span"),c(17),he(18,"date"),a()(),v(19,Rn,2,1,"pre",12),l(20,"div",13)(21,"button",14),S("click",function(){M(e);let o=C();return O(o.onExplain())}),c(22),a(),l(23,"button",14),S("click",function(){M(e);let o=C();return O(o.onLoadImpact())}),c(24),a(),l(25,"button",15),S("click",function(){M(e);let o=C();return O(o.copyShareLink())}),c(26),a()(),v(27,In,7,1,"div",16)(28,Tn,2,1,"div",17),a(),v(29,Fn,18,6,"div",18),l(30,"div",19)(31,"aside",20)(32,"div",21)(33,"span"),c(34,"Files"),a(),v(35,zn,2,1,"span",22),a(),l(36,"div",23),v(37,Bn,10,7,"div",24)(38,jn,2,0,"div",25)(39,Gn,2,0,"div",25),a()(),l(40,"section",26)(41,"details",27)(42,"summary",28),S("click",function(o){M(e);let r=C();return O(r.toggleAnnotations(o))}),c(43),a(),l(44,"div",29),v(45,Hn,11,6,"div",30),l(46,"div",31)(47,"input",32),it("ngModelChange",function(o){M(e);let r=C();return nt(r.commentAuthor,o)||(r.commentAuthor=o),O(o)}),a(),l(48,"textarea",33),it("ngModelChange",function(o){M(e);let r=C();return nt(r.commentDraft,o)||(r.commentDraft=o),O(o)}),a(),l(49,"button",34),S("click",function(){M(e);let o=C();return O(o.addComment())}),c(50,"Post"),a()()()(),b(51,"app-diff-viewer",35),a()(),Ie()}if(i&2){let e=n.ngIf,t=C();s(4),_(e.shortHash),s(2),u("ngForOf",e.tags),s(),u("ngForOf",e.branches),s(),u("ngIf",e.isMerge),s(2),_(e.subject),s(3),Ne("",e.author," <",e.authorEmail,">"),s(4),_(_e(18,29,e.date,"medium")),s(2),u("ngIf",e.body),s(2),u("disabled",t.explaining()),s(),B(" ",t.explaining()?"...":"\u2728 Explain change"," "),s(),u("disabled",t.loadingImpact()),s(),B(" ",t.loadingImpact()?"...":t.impact()?"Refresh impact":"Show impact"," "),s(2),B(" ",t.shareCopied()?"Copied!":"\u{1F517} Share"," "),s(),u("ngIf",t.explanation()),s(),u("ngIf",t.explainError()),s(),u("ngIf",t.impact()),s(6),u("ngIf",t.files().length),s(2),u("ngForOf",t.files())("ngForTrackBy",t.trackByFile),s(),u("ngIf",!t.files().length&&!t.loading()),s(),u("ngIf",t.loading()),s(2),u("open",t.annotationsOpen()),s(2),B(" \u{1F4AC} Notes (",t.comments().length,") "),s(2),u("ngForOf",t.comments()),s(2),tt("ngModel",t.commentAuthor),s(),tt("ngModel",t.commentDraft),s(),u("disabled",!t.commentDraft.trim()),s(2),u("fileInput",t.activeFile())}}function Wn(i,n){i&1&&(l(0,"div",71)(1,"p",72),c(2,"No commit selected"),a(),l(3,"p",73),c(4," Pick a commit from the list, or press "),l(5,"kbd",74),c(6,"\u2318K"),a(),c(7," to open the command palette. "),a()())}var Be=class i{state=f(G);git=f(en);insightsApi=f(tn);annotationsApi=f(Le);router=f(Yt);commit=this.state.selected;impact=x(null);loadingImpact=x(!1);explanation=x(null);explainError=x(null);explaining=x(!1);comments=x([]);annotationsOpen=x(!1);shareCopied=x(!1);commentDraft="";commentAuthor="me";loading=x(!1);files=Jt(Xt(this.commit).pipe(Oe(n=>n?(this.loading.set(!0),this.git.getDiff(n.hash).pipe(_t(()=>W([])))):(this.loading.set(!1),W([])))),{initialValue:[]});activeFileIndex=x(0);activeFile=ee(()=>{let n=this.files();if(!n.length)return null;let e=Math.min(this.activeFileIndex(),n.length-1);return n[e]});constructor(){j(()=>{this.files(),this.activeFileIndex.set(0),this.loading.set(!1)}),j(()=>{let n=this.commit();if(this.impact.set(null),this.explanation.set(null),this.explainError.set(null),this.shareCopied.set(!1),!n){this.comments.set([]);return}this.annotationsApi.list(n.hash).subscribe({next:e=>this.comments.set(e),error:()=>this.comments.set([])})})}trackByFile(n,e){return e.file}selectFile(n){let e=this.files().findIndex(t=>t.file===n.file);e>=0&&this.activeFileIndex.set(e)}openFileHistory(n){this.router.navigate(["/file",encodeURIComponent(n)])}shortPath(n){if(n.length<=32)return n;let e=n.split("/");return e.length<=2?n:e[0]+"/.../"+e.slice(-2).join("/")}onLoadImpact(){let n=this.commit();n&&(this.loadingImpact.set(!0),this.insightsApi.impact(n.hash).subscribe({next:e=>{this.impact.set(e),this.loadingImpact.set(!1)},error:()=>this.loadingImpact.set(!1)}))}onExplain(){let n=this.commit();!n||this.explaining()||(this.explaining.set(!0),this.explainError.set(null),this.insightsApi.explainCommit(n.hash).subscribe({next:e=>{this.explanation.set(e.summary),this.explaining.set(!1)},error:e=>{this.explainError.set(e?.error?.error??"AI explanation unavailable. Set ANTHROPIC_API_KEY or OPENAI_API_KEY."),this.explaining.set(!1)}}))}copyShareLink(){let n=this.commit();if(!n)return;let e=`${window.location.origin}/?commit=${n.hash}`;navigator.clipboard?.writeText(e).then(()=>{this.shareCopied.set(!0),setTimeout(()=>this.shareCopied.set(!1),1500)}).catch(()=>{this.shareCopied.set(!1)})}toggleAnnotations(n){setTimeout(()=>this.annotationsOpen.set(!this.annotationsOpen()),0)}addComment(){let n=this.commit();!n||!this.commentDraft.trim()||this.annotationsApi.add(n.hash,this.commentAuthor||"anonymous",this.commentDraft.trim()).subscribe({next:e=>{this.comments.set([...this.comments(),e]),this.commentDraft=""}})}deleteComment(n){let e=this.commit();e&&this.annotationsApi.remove(e.hash,n).subscribe({next:()=>this.comments.set(this.comments().filter(t=>t.id!==n))})}static \u0275fac=function(e){return new(e||i)};static \u0275cmp=D({type:i,selectors:[["app-commit-detail"]],decls:3,vars:2,consts:[["empty",""],[4,"ngIf","ngIfElse"],[1,"head"],[1,"row"],[1,"hash"],[1,"badges"],["class","badge tag",4,"ngFor","ngForOf"],["class","badge branch",4,"ngFor","ngForOf"],["class","badge merge",4,"ngIf"],[1,"subject"],[1,"meta"],[1,"dot"],["class","body",4,"ngIf"],[1,"actions"],[1,"btn","btn-ghost","btn-sm",3,"click","disabled"],[1,"btn","btn-ghost","btn-sm",3,"click"],["class","ai-card",4,"ngIf"],["class","ai-card error",4,"ngIf"],["class","impact-card",4,"ngIf"],[1,"split"],[1,"files"],[1,"files-header"],["class","count",4,"ngIf"],[1,"files-list"],["class","file-row",4,"ngFor","ngForOf","ngForTrackBy"],["class","files-empty",4,"ngIf"],[1,"diff"],[1,"annotations",3,"open"],[3,"click"],[1,"annot-body"],["class","comment",4,"ngFor","ngForOf"],[1,"comment-form"],["placeholder","Your name",1,"input",3,"ngModelChange","ngModel"],["placeholder","Add a note for your team\u2026",1,"input",3,"ngModelChange","ngModel"],[1,"btn",3,"click","disabled"],[3,"fileInput"],[1,"badge","tag"],[1,"badge","branch"],[1,"badge","merge"],[1,"body"],[1,"ai-card"],[1,"ai-pill"],[1,"ai-text"],[1,"btn","btn-ghost","btn-icon","close",3,"click"],[1,"ai-card","error"],[1,"impact-card"],[1,"impact-head"],[1,"impact-meta"],[3,"impact"],[1,"impact-body"],[1,"modules"],[4,"ngFor","ngForOf"],[1,"related"],[3,"click",4,"ngFor","ngForOf"],[1,"count"],[1,"file-row"],[1,"file",3,"click"],[1,"status-dot"],[1,"path",3,"title"],[1,"counts"],["class","add",4,"ngIf"],["class","del",4,"ngIf"],["title","View file history",1,"file-history",3,"click"],[1,"add"],[1,"del"],[1,"files-empty"],[1,"comment"],[1,"comment-head"],[1,"comment-date"],["title","Delete",1,"btn","btn-ghost","btn-icon",3,"click"],[1,"comment-body"],[1,"placeholder"],[1,"title"],[1,"hint"],[1,"kbd"]],template:function(e,t){if(e&1&&v(0,$n,52,32,"ng-container",1)(1,Wn,8,0,"ng-template",null,0,Ve),e&2){let o=Te(2);u("ngIf",t.commit())("ngIfElse",o)}},dependencies:[T,U,I,Kt,Zt,Qt,qt,nn,Ae,Fe],styles:["[_nghost-%COMP%]{display:flex;flex-direction:column;height:100%;min-height:0;background:var(--bg-app)}.head[_ngcontent-%COMP%]{padding:.85rem 1rem;border-bottom:1px solid var(--border-soft);background:var(--bg-surface)}.row[_ngcontent-%COMP%]{display:flex;align-items:center;gap:.5rem;flex-wrap:wrap;margin-bottom:.4rem}.hash[_ngcontent-%COMP%]{font-family:var(--font-mono);font-size:12px;color:var(--fg-muted);padding:2px 6px;background:var(--bg-surface-2);border:1px solid var(--border-soft);border-radius:4px}.badges[_ngcontent-%COMP%]{display:flex;flex-wrap:wrap;gap:4px}.badge[_ngcontent-%COMP%]{font-size:10px;font-weight:600;padding:2px 6px;border-radius:999px}.badge.tag[_ngcontent-%COMP%]{background:#d9770626;color:var(--warning)}.badge.branch[_ngcontent-%COMP%]{background:var(--accent-soft);color:var(--accent)}.badge.merge[_ngcontent-%COMP%]{background:#8b5cf62e;color:#8b5cf6}.subject[_ngcontent-%COMP%]{font-size:18px;margin:0 0 4px;font-weight:600}.meta[_ngcontent-%COMP%]{display:flex;gap:6px;align-items:center;font-size:12px;color:var(--fg-muted)}.meta[_ngcontent-%COMP%] .dot[_ngcontent-%COMP%]{opacity:.5}.body[_ngcontent-%COMP%]{white-space:pre-wrap;font-family:var(--font-mono);font-size:12px;color:var(--fg-secondary);background:var(--bg-surface-2);border:1px solid var(--border-soft);border-radius:var(--radius-sm);padding:.5rem .75rem;margin-top:.5rem;max-height:160px;overflow:auto}.split[_ngcontent-%COMP%]{flex:1;display:grid;grid-template-columns:280px 1fr;grid-template-rows:minmax(0,1fr);min-height:0;overflow:hidden}.files[_ngcontent-%COMP%]{display:flex;flex-direction:column;min-height:0;background:var(--bg-surface);border-right:1px solid var(--border-soft)}.files-header[_ngcontent-%COMP%]{display:flex;justify-content:space-between;padding:.5rem .85rem;font-size:12px;color:var(--fg-muted);border-bottom:1px solid var(--border-soft)}.count[_ngcontent-%COMP%]{background:var(--bg-surface-2);padding:0 6px;border-radius:999px;font-size:11px}.files-list[_ngcontent-%COMP%]{overflow:auto;flex:1;min-height:0}.file[_ngcontent-%COMP%]{display:grid;grid-template-columns:10px 1fr auto;gap:.5rem;align-items:center;width:100%;padding:.5rem .85rem;border:0;background:transparent;color:inherit;cursor:pointer;text-align:left;border-bottom:1px solid var(--border-soft);font-size:12px}.file[_ngcontent-%COMP%]:hover{background:var(--bg-hover)}.file.selected[_ngcontent-%COMP%]{background:var(--bg-selected)}.file[_ngcontent-%COMP%] .path[_ngcontent-%COMP%]{font-family:var(--font-mono);white-space:nowrap;overflow:hidden;text-overflow:ellipsis;direction:rtl;text-align:left}.status-dot[_ngcontent-%COMP%]{width:8px;height:8px;border-radius:50%;background:var(--accent)}.status-dot[data-status=added][_ngcontent-%COMP%]{background:var(--success)}.status-dot[data-status=deleted][_ngcontent-%COMP%]{background:var(--danger)}.status-dot[data-status=renamed][_ngcontent-%COMP%], .status-dot[data-status=copied][_ngcontent-%COMP%]{background:var(--warning)}.status-dot[data-status=binary][_ngcontent-%COMP%]{background:var(--fg-muted)}.counts[_ngcontent-%COMP%]{display:flex;gap:6px;font-family:var(--font-mono);font-size:11px}.counts[_ngcontent-%COMP%] .add[_ngcontent-%COMP%]{color:var(--success)}.counts[_ngcontent-%COMP%] .del[_ngcontent-%COMP%]{color:var(--danger)}.files-empty[_ngcontent-%COMP%]{padding:1rem;color:var(--fg-muted);font-size:12px;text-align:center}.diff[_ngcontent-%COMP%]{min-width:0;min-height:0;display:flex;flex-direction:column;overflow:hidden}.placeholder[_ngcontent-%COMP%]{flex:1;display:grid;place-items:center;text-align:center;color:var(--fg-muted)}.placeholder[_ngcontent-%COMP%] .title[_ngcontent-%COMP%]{font-size:16px;margin-bottom:4px;color:var(--fg-secondary)}.placeholder[_ngcontent-%COMP%] .hint[_ngcontent-%COMP%]{font-size:13px}.actions[_ngcontent-%COMP%]{display:flex;flex-wrap:wrap;gap:.4rem;margin-top:.6rem}.btn-sm[_ngcontent-%COMP%]{font-size:11px;padding:.3rem .65rem}.ai-card[_ngcontent-%COMP%]{display:flex;align-items:flex-start;gap:.5rem;padding:.55rem .75rem;margin-top:.5rem;background:color-mix(in oklab,var(--accent) 12%,transparent);border-radius:var(--radius-sm);font-size:12px;color:var(--fg-secondary)}.ai-card.error[_ngcontent-%COMP%]{background:#ef44441f;color:var(--danger)}.ai-pill[_ngcontent-%COMP%]{flex-shrink:0;font-size:10px;font-weight:700;letter-spacing:.04em;background:var(--accent);color:var(--accent-fg);padding:1px 5px;border-radius:4px}.ai-text[_ngcontent-%COMP%]{flex:1;line-height:1.5}.ai-card[_ngcontent-%COMP%] .close[_ngcontent-%COMP%]{font-size:14px;line-height:1;padding:0 6px}.impact-card[_ngcontent-%COMP%]{margin:.6rem 1rem;background:var(--bg-surface);border:1px solid var(--border-soft);border-radius:var(--radius-md);padding:.75rem 1rem}.impact-head[_ngcontent-%COMP%]{display:flex;justify-content:space-between;font-weight:600;margin-bottom:.5rem;font-size:13px}.impact-meta[_ngcontent-%COMP%]{color:var(--fg-muted);font-weight:400;font-size:11px}.impact-body[_ngcontent-%COMP%]{display:grid;grid-template-columns:repeat(auto-fit,minmax(160px,1fr));gap:.75rem;font-size:12px}.impact-body[_ngcontent-%COMP%] h4[_ngcontent-%COMP%]{margin:0 0 .4rem;font-size:11px;color:var(--fg-muted);text-transform:uppercase;letter-spacing:.04em}.impact-body[_ngcontent-%COMP%] ul[_ngcontent-%COMP%]{list-style:none;margin:0;padding:0}.impact-body[_ngcontent-%COMP%] li[_ngcontent-%COMP%]{padding:2px 0;word-break:break-all}.modules[_ngcontent-%COMP%] li[_ngcontent-%COMP%]{font-family:var(--font-mono, monospace)}.ripple[_ngcontent-%COMP%] li[_ngcontent-%COMP%]{font-size:11px;color:var(--fg-secondary)}.related[_ngcontent-%COMP%] li[_ngcontent-%COMP%]{cursor:pointer;display:flex;gap:.4rem}.related[_ngcontent-%COMP%] li[_ngcontent-%COMP%]:hover{color:var(--accent)}.related[_ngcontent-%COMP%] code[_ngcontent-%COMP%]{font-family:var(--font-mono, monospace);color:var(--fg-muted);flex-shrink:0}.impact-body[_ngcontent-%COMP%] .muted[_ngcontent-%COMP%]{color:var(--fg-muted);font-style:italic;margin:0;font-size:11px}.file-row[_ngcontent-%COMP%]{display:flex}.file-row[_ngcontent-%COMP%] .file[_ngcontent-%COMP%]{flex:1}.file-history[_ngcontent-%COMP%]{background:transparent;border:0;border-bottom:1px solid var(--border-soft);cursor:pointer;color:var(--fg-muted);padding:0 .6rem;font-size:12px}.file-history[_ngcontent-%COMP%]:hover{background:var(--bg-elevated);color:var(--accent)}.annotations[_ngcontent-%COMP%]{margin:.5rem;background:var(--bg-surface);border:1px solid var(--border-soft);border-radius:var(--radius-sm)}.annotations[_ngcontent-%COMP%] summary[_ngcontent-%COMP%]{padding:.4rem .7rem;cursor:pointer;font-size:12px;color:var(--fg-secondary);-webkit-user-select:none;user-select:none}.annotations[open][_ngcontent-%COMP%] summary[_ngcontent-%COMP%]{border-bottom:1px solid var(--border-soft)}.annot-body[_ngcontent-%COMP%]{padding:.5rem .7rem}.comment[_ngcontent-%COMP%]{padding:.4rem 0;border-bottom:1px dashed var(--border-soft);font-size:12px}.comment[_ngcontent-%COMP%]:last-of-type{border-bottom:0}.comment-head[_ngcontent-%COMP%]{display:flex;align-items:center;gap:.5rem}.comment-date[_ngcontent-%COMP%]{color:var(--fg-muted);font-size:11px;flex:1}.comment-body[_ngcontent-%COMP%]{margin:.2rem 0 0;line-height:1.4;white-space:pre-wrap}.comment-form[_ngcontent-%COMP%]{display:flex;gap:.4rem;flex-direction:column;margin-top:.5rem}.comment-form[_ngcontent-%COMP%] .input[_ngcontent-%COMP%]{width:100%;padding:.35rem .5rem;background:var(--bg-app);border:1px solid var(--border-soft);border-radius:var(--radius-sm);color:var(--fg-primary);font-family:inherit;font-size:12px}.comment-form[_ngcontent-%COMP%] textarea[_ngcontent-%COMP%]{min-height:60px;resize:vertical}.comment-form[_ngcontent-%COMP%] .btn[_ngcontent-%COMP%]{align-self:flex-end}"],changeDetection:0})};var Un=["canvas"],Yn=["scroll"];function Zn(i,n){if(i&1&&b(0,"span",11),i&2){let e=n.$implicit;J("background",e)}}function Qn(i,n){i&1&&(l(0,"div",12),c(1," No commits to draw. "),a())}var k=34,xe=24,je=5.5,rt=16,re=16,at=["#4f46e5","#06b6d4","#f59e0b","#ef4444","#10b981","#8b5cf6","#ec4899","#0ea5e9"],Ge=class i{state=f(G);theme=f(mn);legendColors=at.slice(0,5);graphSummary=ee(()=>{let n=this.state.commits().length,e=this.laneCount;return n?`${n.toLocaleString()} commits across ${e} lane${e===1?"":"s"}`:"Swim-lane visualization"});contentHeight=ee(()=>{let n=this.state.commits().length;return n?re*2+n*k:0});canvasRef;scrollRef;nodes=[];rowByHash=new Map;laneCount=1;hoverRow=-1;onCanvasClick=n=>this.onClick(n);onCanvasMove=n=>this.onMouseMove(n);onCanvasLeave=()=>this.onMouseLeave();scrollRaf=0;onScroll=()=>{this.scrollRaf||(this.scrollRaf=requestAnimationFrame(()=>{this.scrollRaf=0,this.draw()}))};constructor(){j(()=>{this.layout(this.state.commits()),this.draw()}),j(()=>{this.state.selectedHash(),this.theme.resolved(),this.draw()})}ngAfterViewInit(){let n=this.canvasRef.nativeElement;n.addEventListener("click",this.onCanvasClick),n.addEventListener("mousemove",this.onCanvasMove),n.addEventListener("mouseleave",this.onCanvasLeave),this.scrollRef?.nativeElement.addEventListener("scroll",this.onScroll,{passive:!0}),this.draw()}ngOnDestroy(){let n=this.canvasRef?.nativeElement;n?.removeEventListener("click",this.onCanvasClick),n?.removeEventListener("mousemove",this.onCanvasMove),n?.removeEventListener("mouseleave",this.onCanvasLeave),this.scrollRef?.nativeElement.removeEventListener("scroll",this.onScroll),this.scrollRaf&&cancelAnimationFrame(this.scrollRaf)}onResize(){this.draw()}layout(n){if(this.nodes=[],this.rowByHash.clear(),this.hoverRow=-1,!n.length){this.laneCount=1;return}let e=[],t=o=>{let r=e.indexOf(o);if(r>=0)return r;let m=e.indexOf(null);return m>=0?(e[m]=o,m):(e.push(o),e.length-1)};for(let o=0;o<n.length;o++){let r=n[o],m=t(r.hash),h={commit:r,row:o,lane:m};this.nodes.push(h),this.rowByHash.set(r.hash,h);let[g,...d]=r.parents;e[m]=g??null;for(let w of d)if(e.indexOf(w)===-1){let R=e.indexOf(null);R>=0?e[R]=w:e.push(w)}for(;e.length&&e[e.length-1]===null;)e.pop()}this.laneCount=Math.max(1,this.nodes.reduce((o,r)=>Math.max(o,r.lane+1),0))}draw(){let n=this.canvasRef?.nativeElement;if(!n)return;let e=this.scrollRef?.nativeElement,t=window.devicePixelRatio||1,o=rt*2+this.laneCount*xe,r=e?.scrollTop??0,m=e?.clientHeight??0,h=Math.max(o,e?.clientWidth??o),g=Math.max(m||k*8,k);n.width=Math.floor(h*t),n.height=Math.floor(g*t),n.style.width=`${h}px`,n.style.height=`${g}px`,n.style.transform=`translateY(${r}px)`;let d=n.getContext("2d"),w=this.readTheme(n);if(d.setTransform(t,0,0,t,0,-r*t),d.clearRect(0,r,h,g),d.fillStyle=w.surface,d.fillRect(0,r,h,g),!this.nodes.length)return;let R=y=>rt+y*xe+xe/2,Y=y=>re+y*k+k/2,ye=y=>at[y%at.length],p=this.state.selectedHash(),H=k*4,se=Math.max(0,Math.floor((r-re-H)/k)),P=Math.min(this.nodes.length-1,Math.ceil((r+g-re+H)/k)),E=this.nodes.slice(se,P+1);this.drawRows(d,h,R,Y,w,p,E),this.drawGuides(d,Y,w),d.lineCap="round",d.lineJoin="round";for(let y of E)for(let le of y.commit.parents){let $=this.rowByHash.get(le);if(!$)continue;let ne=R(y.lane),Z=Y(y.row),ce=R($.lane),ie=Y($.row);d.strokeStyle=w.shadow,d.lineWidth=4,d.globalAlpha=.35,this.drawEdge(d,ne,Z,ce,ie),d.strokeStyle=ye($.lane),d.lineWidth=y.commit.isMerge?2.6:2.2,d.globalAlpha=p&&p!==y.commit.hash&&p!==$.commit.hash?.55:.9,this.drawEdge(d,ne,Z,ce,ie),d.globalAlpha=1}for(let y of E){let le=R(y.lane),$=Y(y.row),ne=ye(y.lane),Z=y.commit.hash===p,ce=y.row===this.hoverRow,ie=Z?je+2:ce?je+1:je;d.beginPath(),d.arc(le,$,ie+3,0,Math.PI*2),d.fillStyle=w.nodeRing,d.fill(),d.beginPath(),d.arc(le,$,ie,0,Math.PI*2),d.fillStyle=y.commit.isMerge?w.surface:ne,d.fill(),d.lineWidth=y.commit.isMerge||Z?2.5:1.75,d.strokeStyle=ne,d.stroke(),(Z||ce)&&(d.beginPath(),d.arc(le,$,ie+5,0,Math.PI*2),d.strokeStyle=ne,d.globalAlpha=Z?.42:.24,d.lineWidth=2,d.stroke(),d.globalAlpha=1)}}drawRows(n,e,t,o,r,m,h=this.nodes){for(let g of h){let d=o(g.row)-k/2;if(g.row%2===1&&(n.fillStyle=r.rowAlt,n.fillRect(0,d,e,k)),(g.row===this.hoverRow||g.commit.hash===m)&&(n.fillStyle=g.commit.hash===m?r.rowSelected:r.rowHover,this.roundRect(n,6,d+3,e-12,k-6,8),n.fill()),g.commit.branches.length||g.commit.tags.length){let w=t(g.lane)+je+8;this.drawRefPill(n,w,o(g.row),g.commit,r)}}}drawGuides(n,e,t){n.save(),n.strokeStyle=t.guide,n.lineWidth=1,n.setLineDash([3,5]);for(let o=0;o<this.laneCount;o++){let r=rt+o*xe+xe/2;n.beginPath(),n.moveTo(r,re/2),n.lineTo(r,e(this.nodes.length-1)+k/2),n.stroke()}n.restore()}drawEdge(n,e,t,o,r){if(n.beginPath(),n.moveTo(e,t),e===o)n.lineTo(o,r);else{let m=t+Math.min(k*.75,Math.max(12,(r-t)*.36));n.bezierCurveTo(e,m,o,m,o,r)}n.stroke()}drawRefPill(n,e,t,o,r){let m=o.tags[0]??o.branches[0];if(!m)return;let h=m.length>16?`${m.slice(0,15)}...`:m;n.font="600 10px ui-sans-serif, system-ui, sans-serif";let g=Math.min(96,n.measureText(h).width+14),d=18;n.fillStyle=o.tags.length?r.warningSoft:r.accentSoft,this.roundRect(n,e,t-d/2,g,d,999),n.fill(),n.fillStyle=o.tags.length?r.warning:r.accent,n.fillText(h,e+7,t+3.5)}onClick(n){let e=this.nodeFromEvent(n);e&&this.state.selectHash(e.commit.hash)}onMouseMove(n){let e=this.nodeFromEvent(n),t=e?.row??-1;t!==this.hoverRow&&(this.hoverRow=t,this.canvasRef.nativeElement.style.cursor=e?"pointer":"default",this.draw())}onMouseLeave(){this.hoverRow!==-1&&(this.hoverRow=-1,this.canvasRef.nativeElement.style.cursor="default",this.draw())}nodeFromEvent(n){let e=this.scrollRef?.nativeElement,t=e?.getBoundingClientRect();if(!t)return;let o=n.clientY-t.top+(e?.scrollTop??0),r=Math.floor((o-re)/k);return this.nodes[r]}readTheme(n){let e=getComputedStyle(n);return{accent:this.css(e,"--accent","#4f46e5"),accentSoft:this.css(e,"--accent-soft","#eef2ff"),guide:this.css(e,"--graph-guide","rgba(148, 163, 184, 0.28)"),nodeRing:this.css(e,"--graph-node-ring","#ffffff"),rowAlt:this.css(e,"--graph-row-alt","rgba(15, 23, 42, 0.025)"),rowHover:this.css(e,"--graph-row-hover","rgba(79, 70, 229, 0.08)"),rowSelected:this.css(e,"--graph-row-selected","rgba(79, 70, 229, 0.14)"),shadow:this.css(e,"--graph-shadow","rgba(15, 23, 42, 0.12)"),surface:this.css(e,"--bg-surface","#ffffff"),warning:this.css(e,"--warning","#d97706"),warningSoft:"rgba(217, 119, 6, 0.15)"}}css(n,e,t){return n.getPropertyValue(e).trim()||t}roundRect(n,e,t,o,r,m){let h=Math.min(m,o/2,r/2);n.beginPath(),n.moveTo(e+h,t),n.arcTo(e+o,t,e+o,t+r,h),n.arcTo(e+o,t+r,e,t+r,h),n.arcTo(e,t+r,e,t,h),n.arcTo(e,t,e+o,t,h),n.closePath()}static \u0275fac=function(e){return new(e||i)};static \u0275cmp=D({type:i,selectors:[["app-commit-graph"]],viewQuery:function(e,t){if(e&1&&(q(Un,7),q(Yn,7)),e&2){let o;K(o=X())&&(t.canvasRef=o.first),K(o=X())&&(t.scrollRef=o.first)}},hostBindings:function(e,t){e&1&&S("resize",function(){return t.onResize()},Pe)},decls:14,vars:5,consts:[["scroll",""],["canvas",""],[1,"header"],[1,"title"],[1,"hint"],["aria-hidden","true",1,"legend"],["class","swatch",3,"background",4,"ngFor","ngForOf"],[1,"scroll"],[1,"phantom"],["aria-label","Commit graph","role","img"],["class","empty",4,"ngIf"],[1,"swatch"],[1,"empty"]],template:function(e,t){e&1&&(l(0,"div",2)(1,"div",3)(2,"span"),c(3,"Graph"),a(),l(4,"span",4),c(5),a()(),l(6,"div",5),v(7,Zn,1,2,"span",6),a()(),l(8,"div",7,0),b(10,"div",8)(11,"canvas",9,1),v(13,Qn,2,0,"div",10),a()),e&2&&(s(5),_(t.graphSummary()),s(2),u("ngForOf",t.legendColors),s(3),J("height",t.contentHeight(),"px"),s(3),u("ngIf",!t.state.commits().length&&!t.state.loading()))},dependencies:[T,U,I],styles:["[_nghost-%COMP%]{display:flex;flex-direction:column;height:100%;min-height:0;background:var(--bg-surface);border-right:1px solid var(--border-soft)}.header[_ngcontent-%COMP%]{display:flex;align-items:center;justify-content:space-between;gap:.75rem;padding:.6rem .85rem;border-bottom:1px solid var(--border-soft);font-size:12px;color:var(--fg-muted);background:color-mix(in oklab,var(--bg-surface) 96%,var(--bg-surface-2))}.title[_ngcontent-%COMP%]{display:flex;flex-direction:column;gap:1px;min-width:0}.title[_ngcontent-%COMP%] > span[_ngcontent-%COMP%]:first-child{color:var(--fg-primary);font-size:13px;font-weight:600}.hint[_ngcontent-%COMP%]{white-space:nowrap}.legend[_ngcontent-%COMP%]{display:flex;gap:4px;align-items:center;flex:0 0 auto}.swatch[_ngcontent-%COMP%]{width:8px;height:8px;border-radius:999px;box-shadow:0 0 0 2px var(--bg-surface)}.scroll[_ngcontent-%COMP%]{position:relative;flex:1;overflow:auto;min-height:0;background:radial-gradient(circle at 24px 24px,var(--graph-row-alt) 0 1px,transparent 1px 100%),var(--bg-surface);background-size:24px 24px}.phantom[_ngcontent-%COMP%]{width:1px;pointer-events:none}canvas[_ngcontent-%COMP%]{display:block;position:absolute;top:0;left:0;pointer-events:auto;will-change:transform}.empty[_ngcontent-%COMP%]{position:absolute;inset:0;display:grid;place-items:center;padding:1rem;color:var(--fg-muted);font-size:12px;text-align:center}"],changeDetection:0})};function be(i,n=0){return qn(i)?Number(i):arguments.length===2?n:0}function qn(i){return!isNaN(parseFloat(i))&&!isNaN(Number(i))}function pn(i){return i instanceof me?i.nativeElement:i}var st;try{st=typeof Intl<"u"&&Intl.v8BreakIterator}catch{st=!1}var He=(()=>{class i{_platformId=f(Et);isBrowser=this._platformId?Wt(this._platformId):typeof document=="object"&&!!document;EDGE=this.isBrowser&&/(edge)/i.test(navigator.userAgent);TRIDENT=this.isBrowser&&/(msie|trident)/i.test(navigator.userAgent);BLINK=this.isBrowser&&!!(window.chrome||st)&&typeof CSS<"u"&&!this.EDGE&&!this.TRIDENT;WEBKIT=this.isBrowser&&/AppleWebKit/i.test(navigator.userAgent)&&!this.BLINK&&!this.EDGE&&!this.TRIDENT;IOS=this.isBrowser&&/iPad|iPhone|iPod/.test(navigator.userAgent)&&!("MSStream"in window);FIREFOX=this.isBrowser&&/(firefox|minefield)/i.test(navigator.userAgent);ANDROID=this.isBrowser&&/android/i.test(navigator.userAgent)&&!this.TRIDENT;SAFARI=this.isBrowser&&/safari/i.test(navigator.userAgent)&&this.WEBKIT;constructor(){}static \u0275fac=function(t){return new(t||i)};static \u0275prov=V({token:i,factory:i.\u0275fac,providedIn:"root"})}return i})();var Kn=new Q("cdk-dir-doc",{providedIn:"root",factory:Xn});function Xn(){return f(De)}var Jn=/^(ar|ckb|dv|he|iw|fa|nqo|ps|sd|ug|ur|yi|.*[-_](Adlm|Arab|Hebr|Nkoo|Rohg|Thaa))(?!.*[-_](Latn|Cyrl)($|-|_))($|-|_)/i;function ei(i){let n=i?.toLowerCase()||"";return n==="auto"&&typeof navigator<"u"&&navigator?.language?Jn.test(navigator.language)?"rtl":"ltr":n==="rtl"?"rtl":"ltr"}var fn=(()=>{class i{get value(){return this.valueSignal()}valueSignal=x("ltr");change=new Rt;constructor(){let e=f(Kn,{optional:!0});if(e){let t=e.body?e.body.dir:null,o=e.documentElement?e.documentElement.dir:null;this.valueSignal.set(ei(t||o||"ltr"))}}ngOnDestroy(){this.change.complete()}static \u0275fac=function(t){return new(t||i)};static \u0275prov=V({token:i,factory:i.\u0275fac,providedIn:"root"})}return i})();var A=(function(i){return i[i.NORMAL=0]="NORMAL",i[i.NEGATED=1]="NEGATED",i[i.INVERTED=2]="INVERTED",i})(A||{}),$e,te;function gn(){if(te==null){if(typeof document!="object"||!document||typeof Element!="function"||!Element)return te=!1,te;if(document.documentElement?.style&&"scrollBehavior"in document.documentElement.style)te=!0;else{let i=Element.prototype.scrollTo;i?te=!/\{\s*\[native code\]\s*\}/.test(i.toString()):te=!1}}return te}function ae(){if(typeof document!="object"||!document)return A.NORMAL;if($e==null){let i=document.createElement("div"),n=i.style;i.dir="rtl",n.width="1px",n.overflow="auto",n.visibility="hidden",n.pointerEvents="none",n.position="absolute";let e=document.createElement("div"),t=e.style;t.width="2px",t.height="1px",i.appendChild(e),document.body.appendChild(i),$e=A.NORMAL,i.scrollLeft===0&&(i.scrollLeft=1,$e=i.scrollLeft===0?A.NEGATED:A.INVERTED),i.remove()}return $e}var lt=(()=>{class i{static \u0275fac=function(t){return new(t||i)};static \u0275mod=pe({type:i});static \u0275inj=de({})}return i})();var We=class{};function un(i){return i&&typeof i.connect=="function"&&!(i instanceof ft)}var Ue=class extends We{_data;constructor(n){super(),this._data=n}connect(){return Se(this._data)?this._data:W(this._data)}disconnect(){}},we=(function(i){return i[i.REPLACED=0]="REPLACED",i[i.INSERTED=1]="INSERTED",i[i.MOVED=2]="MOVED",i[i.REMOVED=3]="REMOVED",i})(we||{}),ct=new Q("_ViewRepeater"),Ye=class{viewCacheSize=20;_viewCache=[];applyChanges(n,e,t,o,r){n.forEachOperation((m,h,g)=>{let d,w;if(m.previousIndex==null){let R=()=>t(m,h,g);d=this._insertView(R,g,e,o(m)),w=d?we.INSERTED:we.REPLACED}else g==null?(this._detachAndCacheView(h,e),w=we.REMOVED):(d=this._moveView(h,g,e,o(m)),w=we.MOVED);r&&r({context:d?.context,operation:w,record:m})})}detach(){for(let n of this._viewCache)n.destroy();this._viewCache=[]}_insertView(n,e,t,o){let r=this._insertViewFromCache(e,t);if(r){r.context.$implicit=o;return}let m=n();return t.createEmbeddedView(m.templateRef,m.context,m.index)}_detachAndCacheView(n,e){let t=e.detach(n);this._maybeCacheView(t,e)}_moveView(n,e,t,o){let r=t.get(n);return t.move(r,e),r.context.$implicit=o,r}_maybeCacheView(n,e){if(this._viewCache.length<this.viewCacheSize)this._viewCache.push(n);else{let t=e.indexOf(n);t===-1?n.destroy():e.remove(t)}}_insertViewFromCache(n,e){let t=this._viewCache.pop();return t&&e.insert(t,n),t||null}};var ti=["contentWrapper"],ni=["*"],Cn=new Q("VIRTUAL_SCROLL_STRATEGY"),dt=class{_scrolledIndexChange=new N;scrolledIndexChange=this._scrolledIndexChange.pipe(vt());_viewport=null;_itemSize;_minBufferPx;_maxBufferPx;constructor(n,e,t){this._itemSize=n,this._minBufferPx=e,this._maxBufferPx=t}attach(n){this._viewport=n,this._updateTotalContentSize(),this._updateRenderedRange()}detach(){this._scrolledIndexChange.complete(),this._viewport=null}updateItemAndBufferSize(n,e,t){t<e,this._itemSize=n,this._minBufferPx=e,this._maxBufferPx=t,this._updateTotalContentSize(),this._updateRenderedRange()}onContentScrolled(){this._updateRenderedRange()}onDataLengthChanged(){this._updateTotalContentSize(),this._updateRenderedRange()}onContentRendered(){}onRenderedOffsetChanged(){}scrollToIndex(n,e){this._viewport&&this._viewport.scrollToOffset(n*this._itemSize,e)}_updateTotalContentSize(){this._viewport&&this._viewport.setTotalContentSize(this._viewport.getDataLength()*this._itemSize)}_updateRenderedRange(){if(!this._viewport)return;let n=this._viewport.getRenderedRange(),e={start:n.start,end:n.end},t=this._viewport.getViewportSize(),o=this._viewport.getDataLength(),r=this._viewport.measureScrollOffset(),m=this._itemSize>0?r/this._itemSize:0;if(e.end>o){let g=Math.ceil(t/this._itemSize),d=Math.max(0,Math.min(m,o-g));m!=d&&(m=d,r=d*this._itemSize,e.start=Math.floor(m)),e.end=Math.max(0,Math.min(o,e.start+g))}let h=r-e.start*this._itemSize;if(h<this._minBufferPx&&e.start!=0){let g=Math.ceil((this._maxBufferPx-h)/this._itemSize);e.start=Math.max(0,e.start-g),e.end=Math.min(o,Math.ceil(m+(t+this._minBufferPx)/this._itemSize))}else{let g=e.end*this._itemSize-(r+t);if(g<this._minBufferPx&&e.end!=o){let d=Math.ceil((this._maxBufferPx-g)/this._itemSize);d>0&&(e.end=Math.min(o,e.end+d),e.start=Math.max(0,Math.floor(m-this._minBufferPx/this._itemSize)))}}this._viewport.setRenderedRange(e),this._viewport.setRenderedContentOffset(Math.round(this._itemSize*e.start)),this._scrolledIndexChange.next(Math.floor(m))}};function ii(i){return i._scrollStrategy}var xn=(()=>{class i{get itemSize(){return this._itemSize}set itemSize(e){this._itemSize=be(e)}_itemSize=20;get minBufferPx(){return this._minBufferPx}set minBufferPx(e){this._minBufferPx=be(e)}_minBufferPx=100;get maxBufferPx(){return this._maxBufferPx}set maxBufferPx(e){this._maxBufferPx=be(e)}_maxBufferPx=200;_scrollStrategy=new dt(this.itemSize,this.minBufferPx,this.maxBufferPx);ngOnChanges(){this._scrollStrategy.updateItemAndBufferSize(this.itemSize,this.minBufferPx,this.maxBufferPx)}static \u0275fac=function(t){return new(t||i)};static \u0275dir=oe({type:i,selectors:[["cdk-virtual-scroll-viewport","itemSize",""]],inputs:{itemSize:"itemSize",minBufferPx:"minBufferPx",maxBufferPx:"maxBufferPx"},features:[ue([{provide:Cn,useFactory:ii,deps:[bt(()=>i)]}]),ke]})}return i})(),oi=20,ri=(()=>{class i{_ngZone=f(fe);_platform=f(He);_renderer=f(Je).createRenderer(null,null);_cleanupGlobalListener;constructor(){}_scrolled=new N;_scrolledCount=0;scrollContainers=new Map;register(e){this.scrollContainers.has(e)||this.scrollContainers.set(e,e.elementScrolled().subscribe(()=>this._scrolled.next(e)))}deregister(e){let t=this.scrollContainers.get(e);t&&(t.unsubscribe(),this.scrollContainers.delete(e))}scrolled(e=oi){return this._platform.isBrowser?new Ke(t=>{this._cleanupGlobalListener||(this._cleanupGlobalListener=this._ngZone.runOutsideAngular(()=>this._renderer.listen("document","scroll",()=>this._scrolled.next())));let o=e>0?this._scrolled.pipe(Me(e)).subscribe(t):this._scrolled.subscribe(t);return this._scrolledCount++,()=>{o.unsubscribe(),this._scrolledCount--,this._scrolledCount||(this._cleanupGlobalListener?.(),this._cleanupGlobalListener=void 0)}}):W()}ngOnDestroy(){this._cleanupGlobalListener?.(),this._cleanupGlobalListener=void 0,this.scrollContainers.forEach((e,t)=>this.deregister(t)),this._scrolled.complete()}ancestorScrolled(e,t){let o=this.getAncestorScrollContainers(e);return this.scrolled(t).pipe(ht(r=>!r||o.indexOf(r)>-1))}getAncestorScrollContainers(e){let t=[];return this.scrollContainers.forEach((o,r)=>{this._scrollableContainsElement(r,e)&&t.push(r)}),t}_scrollableContainsElement(e,t){let o=pn(t),r=e.getElementRef().nativeElement;do if(o==r)return!0;while(o=o.parentElement);return!1}static \u0275fac=function(t){return new(t||i)};static \u0275prov=V({token:i,factory:i.\u0275fac,providedIn:"root"})}return i})(),bn=(()=>{class i{elementRef=f(me);scrollDispatcher=f(ri);ngZone=f(fe);dir=f(fn,{optional:!0});_scrollElement=this.elementRef.nativeElement;_destroyed=new N;_renderer=f(kt);_cleanupScroll;_elementScrolled=new N;constructor(){}ngOnInit(){this._cleanupScroll=this.ngZone.runOutsideAngular(()=>this._renderer.listen(this._scrollElement,"scroll",e=>this._elementScrolled.next(e))),this.scrollDispatcher.register(this)}ngOnDestroy(){this._cleanupScroll?.(),this._elementScrolled.complete(),this.scrollDispatcher.deregister(this),this._destroyed.next(),this._destroyed.complete()}elementScrolled(){return this._elementScrolled}getElementRef(){return this.elementRef}scrollTo(e){let t=this.elementRef.nativeElement,o=this.dir&&this.dir.value=="rtl";e.left==null&&(e.left=o?e.end:e.start),e.right==null&&(e.right=o?e.start:e.end),e.bottom!=null&&(e.top=t.scrollHeight-t.clientHeight-e.bottom),o&&ae()!=A.NORMAL?(e.left!=null&&(e.right=t.scrollWidth-t.clientWidth-e.left),ae()==A.INVERTED?e.left=e.right:ae()==A.NEGATED&&(e.left=e.right?-e.right:e.right)):e.right!=null&&(e.left=t.scrollWidth-t.clientWidth-e.right),this._applyScrollToOptions(e)}_applyScrollToOptions(e){let t=this.elementRef.nativeElement;gn()?t.scrollTo(e):(e.top!=null&&(t.scrollTop=e.top),e.left!=null&&(t.scrollLeft=e.left))}measureScrollOffset(e){let t="left",o="right",r=this.elementRef.nativeElement;if(e=="top")return r.scrollTop;if(e=="bottom")return r.scrollHeight-r.clientHeight-r.scrollTop;let m=this.dir&&this.dir.value=="rtl";return e=="start"?e=m?o:t:e=="end"&&(e=m?t:o),m&&ae()==A.INVERTED?e==t?r.scrollWidth-r.clientWidth-r.scrollLeft:r.scrollLeft:m&&ae()==A.NEGATED?e==t?r.scrollLeft+r.scrollWidth-r.clientWidth:-r.scrollLeft:e==t?r.scrollLeft:r.scrollWidth-r.clientWidth-r.scrollLeft}static \u0275fac=function(t){return new(t||i)};static \u0275dir=oe({type:i,selectors:[["","cdk-scrollable",""],["","cdkScrollable",""]]})}return i})(),ai=20,si=(()=>{class i{_platform=f(He);_listeners;_viewportSize;_change=new N;_document=f(De);constructor(){let e=f(fe),t=f(Je).createRenderer(null,null);e.runOutsideAngular(()=>{if(this._platform.isBrowser){let o=r=>this._change.next(r);this._listeners=[t.listen("window","resize",o),t.listen("window","orientationchange",o)]}this.change().subscribe(()=>this._viewportSize=null)})}ngOnDestroy(){this._listeners?.forEach(e=>e()),this._change.complete()}getViewportSize(){this._viewportSize||this._updateViewportSize();let e={width:this._viewportSize.width,height:this._viewportSize.height};return this._platform.isBrowser||(this._viewportSize=null),e}getViewportRect(){let e=this.getViewportScrollPosition(),{width:t,height:o}=this.getViewportSize();return{top:e.top,left:e.left,bottom:e.top+o,right:e.left+t,height:o,width:t}}getViewportScrollPosition(){if(!this._platform.isBrowser)return{top:0,left:0};let e=this._document,t=this._getWindow(),o=e.documentElement,r=o.getBoundingClientRect(),m=-r.top||e.body.scrollTop||t.scrollY||o.scrollTop||0,h=-r.left||e.body.scrollLeft||t.scrollX||o.scrollLeft||0;return{top:m,left:h}}change(e=ai){return e>0?this._change.pipe(Me(e)):this._change}_getWindow(){return this._document.defaultView||window}_updateViewportSize(){let e=this._getWindow();this._viewportSize=this._platform.isBrowser?{width:e.innerWidth,height:e.innerHeight}:{width:0,height:0}}static \u0275fac=function(t){return new(t||i)};static \u0275prov=V({token:i,factory:i.\u0275fac,providedIn:"root"})}return i})(),hn=new Q("VIRTUAL_SCROLLABLE"),li=(()=>{class i extends bn{constructor(){super()}measureViewportSize(e){let t=this.elementRef.nativeElement;return e==="horizontal"?t.clientWidth:t.clientHeight}static \u0275fac=function(t){return new(t||i)};static \u0275dir=oe({type:i,features:[et]})}return i})();function ci(i,n){return i.start==n.start&&i.end==n.end}var di=typeof requestAnimationFrame<"u"?ut:gt,mt=(()=>{class i extends li{elementRef=f(me);_changeDetectorRef=f(Gt);_scrollStrategy=f(Cn,{optional:!0});scrollable=f(hn,{optional:!0});_platform=f(He);_detachedSubject=new N;_renderedRangeSubject=new N;get orientation(){return this._orientation}set orientation(e){this._orientation!==e&&(this._orientation=e,this._calculateSpacerSize())}_orientation="vertical";appendOnly=!1;scrolledIndexChange=new Ke(e=>this._scrollStrategy.scrolledIndexChange.subscribe(t=>Promise.resolve().then(()=>this.ngZone.run(()=>e.next(t)))));_contentWrapper;renderedRangeStream=this._renderedRangeSubject;_totalContentSize=0;_totalContentWidth=x("");_totalContentHeight=x("");_renderedContentTransform;_renderedRange={start:0,end:0};_dataLength=0;_viewportSize=0;_forOf;_renderedContentOffset=0;_renderedContentOffsetNeedsRewrite=!1;_changeDetectionNeeded=x(!1);_runAfterChangeDetection=[];_viewportChanges=pt.EMPTY;_injector=f(yt);_isDestroyed=!1;constructor(){super();let e=f(si);this._scrollStrategy,this._viewportChanges=e.change().subscribe(()=>{this.checkViewportSize()}),this.scrollable||(this.elementRef.nativeElement.classList.add("cdk-virtual-scrollable"),this.scrollable=this);let t=j(()=>{this._changeDetectionNeeded()&&this._doChangeDetection()},{injector:f(Tt).injector});f(St).onDestroy(()=>void t.destroy())}ngOnInit(){this._platform.isBrowser&&(this.scrollable===this&&super.ngOnInit(),this.ngZone.runOutsideAngular(()=>Promise.resolve().then(()=>{this._measureViewportSize(),this._scrollStrategy.attach(this),this.scrollable.elementScrolled().pipe(Xe(null),Me(0,di),Ee(this._destroyed)).subscribe(()=>this._scrollStrategy.onContentScrolled()),this._markChangeDetectionNeeded()})))}ngOnDestroy(){this.detach(),this._scrollStrategy.detach(),this._renderedRangeSubject.complete(),this._detachedSubject.complete(),this._viewportChanges.unsubscribe(),this._isDestroyed=!0,super.ngOnDestroy()}attach(e){this._forOf,this.ngZone.runOutsideAngular(()=>{this._forOf=e,this._forOf.dataStream.pipe(Ee(this._detachedSubject)).subscribe(t=>{let o=t.length;o!==this._dataLength&&(this._dataLength=o,this._scrollStrategy.onDataLengthChanged()),this._doChangeDetection()})})}detach(){this._forOf=null,this._detachedSubject.next()}getDataLength(){return this._dataLength}getViewportSize(){return this._viewportSize}getRenderedRange(){return this._renderedRange}measureBoundingClientRectWithScrollOffset(e){return this.getElementRef().nativeElement.getBoundingClientRect()[e]}setTotalContentSize(e){this._totalContentSize!==e&&(this._totalContentSize=e,this._calculateSpacerSize(),this._markChangeDetectionNeeded())}setRenderedRange(e){ci(this._renderedRange,e)||(this.appendOnly&&(e={start:0,end:Math.max(this._renderedRange.end,e.end)}),this._renderedRangeSubject.next(this._renderedRange=e),this._markChangeDetectionNeeded(()=>this._scrollStrategy.onContentRendered()))}getOffsetToRenderedContentStart(){return this._renderedContentOffsetNeedsRewrite?null:this._renderedContentOffset}setRenderedContentOffset(e,t="to-start"){e=this.appendOnly&&t==="to-start"?0:e;let o=this.dir&&this.dir.value=="rtl",r=this.orientation=="horizontal",m=r?"X":"Y",g=`translate${m}(${Number((r&&o?-1:1)*e)}px)`;this._renderedContentOffset=e,t==="to-end"&&(g+=` translate${m}(-100%)`,this._renderedContentOffsetNeedsRewrite=!0),this._renderedContentTransform!=g&&(this._renderedContentTransform=g,this._markChangeDetectionNeeded(()=>{this._renderedContentOffsetNeedsRewrite?(this._renderedContentOffset-=this.measureRenderedContentSize(),this._renderedContentOffsetNeedsRewrite=!1,this.setRenderedContentOffset(this._renderedContentOffset)):this._scrollStrategy.onRenderedOffsetChanged()}))}scrollToOffset(e,t="auto"){let o={behavior:t};this.orientation==="horizontal"?o.start=e:o.top=e,this.scrollable.scrollTo(o)}scrollToIndex(e,t="auto"){this._scrollStrategy.scrollToIndex(e,t)}measureScrollOffset(e){let t;return this.scrollable==this?t=o=>super.measureScrollOffset(o):t=o=>this.scrollable.measureScrollOffset(o),Math.max(0,t(e??(this.orientation==="horizontal"?"start":"top"))-this.measureViewportOffset())}measureViewportOffset(e){let t,o="left",r="right",m=this.dir?.value=="rtl";e=="start"?t=m?r:o:e=="end"?t=m?o:r:e?t=e:t=this.orientation==="horizontal"?"left":"top";let h=this.scrollable.measureBoundingClientRectWithScrollOffset(t);return this.elementRef.nativeElement.getBoundingClientRect()[t]-h}measureRenderedContentSize(){let e=this._contentWrapper.nativeElement;return this.orientation==="horizontal"?e.offsetWidth:e.offsetHeight}measureRangeSize(e){return this._forOf?this._forOf.measureRangeSize(e,this.orientation):0}checkViewportSize(){this._measureViewportSize(),this._scrollStrategy.onDataLengthChanged()}_measureViewportSize(){this._viewportSize=this.scrollable.measureViewportSize(this.orientation)}_markChangeDetectionNeeded(e){e&&this._runAfterChangeDetection.push(e),!jt(this._changeDetectionNeeded)&&this.ngZone.runOutsideAngular(()=>{Promise.resolve().then(()=>{this.ngZone.run(()=>{this._changeDetectionNeeded.set(!0)})})})}_doChangeDetection(){this._isDestroyed||this.ngZone.run(()=>{this._changeDetectorRef.markForCheck(),this._contentWrapper.nativeElement.style.transform=this._renderedContentTransform,It(()=>{this._changeDetectionNeeded.set(!1);let e=this._runAfterChangeDetection;this._runAfterChangeDetection=[];for(let t of e)t()},{injector:this._injector})})}_calculateSpacerSize(){this._totalContentHeight.set(this.orientation==="horizontal"?"":`${this._totalContentSize}px`),this._totalContentWidth.set(this.orientation==="horizontal"?`${this._totalContentSize}px`:"")}static \u0275fac=function(t){return new(t||i)};static \u0275cmp=D({type:i,selectors:[["cdk-virtual-scroll-viewport"]],viewQuery:function(t,o){if(t&1&&q(ti,7),t&2){let r;K(r=X())&&(o._contentWrapper=r.first)}},hostAttrs:[1,"cdk-virtual-scroll-viewport"],hostVars:4,hostBindings:function(t,o){t&2&&z("cdk-virtual-scroll-orientation-horizontal",o.orientation==="horizontal")("cdk-virtual-scroll-orientation-vertical",o.orientation!=="horizontal")},inputs:{orientation:"orientation",appendOnly:[2,"appendOnly","appendOnly",$t]},outputs:{scrolledIndexChange:"scrolledIndexChange"},features:[ue([{provide:bn,useFactory:(e,t)=>e||t,deps:[[new Ot,new Mt(hn)],i]}]),et],ngContentSelectors:ni,decls:4,vars:4,consts:[["contentWrapper",""],[1,"cdk-virtual-scroll-content-wrapper"],[1,"cdk-virtual-scroll-spacer"]],template:function(t,o){t&1&&(zt(),Nt(0,"div",1,0),Lt(2),Vt(),Ft(3,"div",2)),t&2&&(s(3),J("width",o._totalContentWidth())("height",o._totalContentHeight()))},styles:[`cdk-virtual-scroll-viewport{display:block;position:relative;transform:translateZ(0)}.cdk-virtual-scrollable{overflow:auto;will-change:scroll-position;contain:strict}.cdk-virtual-scroll-content-wrapper{position:absolute;top:0;left:0;contain:content}[dir=rtl] .cdk-virtual-scroll-content-wrapper{right:0;left:auto}.cdk-virtual-scroll-orientation-horizontal .cdk-virtual-scroll-content-wrapper{min-height:100%}.cdk-virtual-scroll-orientation-horizontal .cdk-virtual-scroll-content-wrapper>dl:not([cdkVirtualFor]),.cdk-virtual-scroll-orientation-horizontal .cdk-virtual-scroll-content-wrapper>ol:not([cdkVirtualFor]),.cdk-virtual-scroll-orientation-horizontal .cdk-virtual-scroll-content-wrapper>table:not([cdkVirtualFor]),.cdk-virtual-scroll-orientation-horizontal .cdk-virtual-scroll-content-wrapper>ul:not([cdkVirtualFor]){padding-left:0;padding-right:0;margin-left:0;margin-right:0;border-left-width:0;border-right-width:0;outline:none}.cdk-virtual-scroll-orientation-vertical .cdk-virtual-scroll-content-wrapper{min-width:100%}.cdk-virtual-scroll-orientation-vertical .cdk-virtual-scroll-content-wrapper>dl:not([cdkVirtualFor]),.cdk-virtual-scroll-orientation-vertical .cdk-virtual-scroll-content-wrapper>ol:not([cdkVirtualFor]),.cdk-virtual-scroll-orientation-vertical .cdk-virtual-scroll-content-wrapper>table:not([cdkVirtualFor]),.cdk-virtual-scroll-orientation-vertical .cdk-virtual-scroll-content-wrapper>ul:not([cdkVirtualFor]){padding-top:0;padding-bottom:0;margin-top:0;margin-bottom:0;border-top-width:0;border-bottom-width:0;outline:none}.cdk-virtual-scroll-spacer{height:1px;transform-origin:0 0;flex:0 0 auto}[dir=rtl] .cdk-virtual-scroll-spacer{transform-origin:100% 0}
|
|
2
|
+
`],encapsulation:2,changeDetection:0})}return i})();function _n(i,n,e){let t=e;if(!t.getBoundingClientRect)return 0;let o=t.getBoundingClientRect();return i==="horizontal"?n==="start"?o.left:o.right:n==="start"?o.top:o.bottom}var wn=(()=>{class i{_viewContainerRef=f(Pt);_template=f(Dt);_differs=f(Ht);_viewRepeater=f(ct);_viewport=f(mt,{skipSelf:!0});viewChange=new N;_dataSourceChanges=new N;get cdkVirtualForOf(){return this._cdkVirtualForOf}set cdkVirtualForOf(e){this._cdkVirtualForOf=e,un(e)?this._dataSourceChanges.next(e):this._dataSourceChanges.next(new Ue(Se(e)?e:Array.from(e||[])))}_cdkVirtualForOf;get cdkVirtualForTrackBy(){return this._cdkVirtualForTrackBy}set cdkVirtualForTrackBy(e){this._needsUpdate=!0,this._cdkVirtualForTrackBy=e?(t,o)=>e(t+(this._renderedRange?this._renderedRange.start:0),o):void 0}_cdkVirtualForTrackBy;set cdkVirtualForTemplate(e){e&&(this._needsUpdate=!0,this._template=e)}get cdkVirtualForTemplateCacheSize(){return this._viewRepeater.viewCacheSize}set cdkVirtualForTemplateCacheSize(e){this._viewRepeater.viewCacheSize=be(e)}dataStream=this._dataSourceChanges.pipe(Xe(null),Ct(),Oe(([e,t])=>this._changeDataSource(e,t)),xt(1));_differ=null;_data;_renderedItems;_renderedRange;_needsUpdate=!1;_destroyed=new N;constructor(){let e=f(fe);this.dataStream.subscribe(t=>{this._data=t,this._onRenderedDataChange()}),this._viewport.renderedRangeStream.pipe(Ee(this._destroyed)).subscribe(t=>{this._renderedRange=t,this.viewChange.observers.length&&e.run(()=>this.viewChange.next(this._renderedRange)),this._onRenderedDataChange()}),this._viewport.attach(this)}measureRangeSize(e,t){if(e.start>=e.end)return 0;e.start<this._renderedRange.start||e.end>this._renderedRange.end;let o=e.start-this._renderedRange.start,r=e.end-e.start,m,h;for(let g=0;g<r;g++){let d=this._viewContainerRef.get(g+o);if(d&&d.rootNodes.length){m=h=d.rootNodes[0];break}}for(let g=r-1;g>-1;g--){let d=this._viewContainerRef.get(g+o);if(d&&d.rootNodes.length){h=d.rootNodes[d.rootNodes.length-1];break}}return m&&h?_n(t,"end",h)-_n(t,"start",m):0}ngDoCheck(){if(this._differ&&this._needsUpdate){let e=this._differ.diff(this._renderedItems);e?this._applyChanges(e):this._updateContext(),this._needsUpdate=!1}}ngOnDestroy(){this._viewport.detach(),this._dataSourceChanges.next(void 0),this._dataSourceChanges.complete(),this.viewChange.complete(),this._destroyed.next(),this._destroyed.complete(),this._viewRepeater.detach()}_onRenderedDataChange(){this._renderedRange&&(this._renderedItems=this._data.slice(this._renderedRange.start,this._renderedRange.end),this._differ||(this._differ=this._differs.find(this._renderedItems).create((e,t)=>this.cdkVirtualForTrackBy?this.cdkVirtualForTrackBy(e,t):t)),this._needsUpdate=!0)}_changeDataSource(e,t){return e&&e.disconnect(this),this._needsUpdate=!0,t?t.connect(this):W()}_updateContext(){let e=this._data.length,t=this._viewContainerRef.length;for(;t--;){let o=this._viewContainerRef.get(t);o.context.index=this._renderedRange.start+t,o.context.count=e,this._updateComputedContextProperties(o.context),o.detectChanges()}}_applyChanges(e){this._viewRepeater.applyChanges(e,this._viewContainerRef,(r,m,h)=>this._getEmbeddedViewArgs(r,h),r=>r.item),e.forEachIdentityChange(r=>{let m=this._viewContainerRef.get(r.currentIndex);m.context.$implicit=r.item});let t=this._data.length,o=this._viewContainerRef.length;for(;o--;){let r=this._viewContainerRef.get(o);r.context.index=this._renderedRange.start+o,r.context.count=t,this._updateComputedContextProperties(r.context)}}_updateComputedContextProperties(e){e.first=e.index===0,e.last=e.index===e.count-1,e.even=e.index%2===0,e.odd=!e.even}_getEmbeddedViewArgs(e,t){return{templateRef:this._template,context:{$implicit:e.item,cdkVirtualForOf:this._cdkVirtualForOf,index:-1,count:-1,first:!1,last:!1,odd:!1,even:!1},index:t}}static ngTemplateContextGuard(e,t){return!0}static \u0275fac=function(t){return new(t||i)};static \u0275dir=oe({type:i,selectors:[["","cdkVirtualFor","","cdkVirtualForOf",""]],inputs:{cdkVirtualForOf:"cdkVirtualForOf",cdkVirtualForTrackBy:"cdkVirtualForTrackBy",cdkVirtualForTemplate:"cdkVirtualForTemplate",cdkVirtualForTemplateCacheSize:"cdkVirtualForTemplateCacheSize"},features:[ue([{provide:ct,useClass:Ye}])]})}return i})();var vn=(()=>{class i{static \u0275fac=function(t){return new(t||i)};static \u0275mod=pe({type:i});static \u0275inj=de({})}return i})(),yn=(()=>{class i{static \u0275fac=function(t){return new(t||i)};static \u0275mod=pe({type:i});static \u0275inj=de({imports:[lt,vn,lt,vn]})}return i})();function pi(i,n){i&1&&b(0,"span",19)}function fi(i,n){if(i&1&&(l(0,"span",23),c(1),a()),i&2){let e=n.$implicit;s(),_(e)}}function gi(i,n){if(i&1&&(l(0,"span",24),c(1),a()),i&2){let e=n.$implicit;s(),_(e)}}function ui(i,n){if(i&1&&(l(0,"span",20),v(1,fi,2,1,"span",21)(2,gi,2,1,"span",22),a()),i&2){let e=C().$implicit;s(),u("ngForOf",e.tags),s(),u("ngForOf",e.branches)}}function hi(i,n){if(i&1){let e=F();l(0,"button",7),S("click",function(){let o=M(e).$implicit,r=C();return O(r.select(o))}),l(1,"span",8),b(2,"span",9),v(3,pi,1,0,"span",10),a(),l(4,"span",11)(5,"span",12),c(6),a(),l(7,"span",13)(8,"span",14),c(9),a(),l(10,"span",15),c(11,"\u2022"),a(),l(12,"span",16),c(13),a(),l(14,"span",15),c(15,"\u2022"),a(),l(16,"span",17),c(17),he(18,"date"),a()()(),v(19,ui,3,2,"span",18),a()}if(i&2){let e=n.$implicit,t=n.index,o=C();z("selected",e.hash===o.selectedHash()),ge("aria-current",e.hash===o.selectedHash()?"true":null),s(2),J("background",o.laneColor(e)),z("merge",e.isMerge),s(),u("ngIf",t<o.commits().length-1),s(2),u("title",e.subject),s(),_(e.subject),s(3),_(e.shortHash),s(4),_(e.author),s(4),_(_e(18,14,e.date,"MMM d, y, h:mm a")),s(2),u("ngIf",e.branches.length||e.tags.length)}}function _i(i,n){i&1&&(l(0,"div",25)(1,"p"),c(2,"No commits match your filters."),a()())}var Ze=class i{state=f(G);commits=this.state.commits;selectedHash=this.state.selectedHash;trackByHash(n,e){return e.hash}select(n){this.state.selectHash(n.hash)}laneColors=["#4f46e5","#06b6d4","#f59e0b","#ef4444","#10b981","#8b5cf6"];laneColor(n){let e=0,t=n.branches[0]??n.parents[0]??n.hash;for(let o=0;o<t.length;o++)e=e*31+t.charCodeAt(o)>>>0;return this.laneColors[e%this.laneColors.length]}onKey(n){if(!this.isTyping(n.target)){if(n.key==="j")n.preventDefault(),this.state.selectByOffset(1);else if(n.key==="k")n.preventDefault(),this.state.selectByOffset(-1);else if(n.key==="g"){n.preventDefault();let e=this.state.commits();e.length&&this.state.selectHash(e[0].hash)}else if(n.key==="G"){n.preventDefault();let e=this.state.commits();e.length&&this.state.selectHash(e[e.length-1].hash)}}}isTyping(n){return n instanceof HTMLElement?["INPUT","TEXTAREA","SELECT"].includes(n.tagName)||n.isContentEditable:!1}static \u0275fac=function(e){return new(e||i)};static \u0275cmp=D({type:i,selectors:[["app-commit-list"]],hostBindings:function(e,t){e&1&&S("keydown",function(r){return t.onKey(r)},Pe)},decls:13,vars:6,consts:[[1,"header"],[1,"count"],[1,"hint"],[1,"kbd"],["minBufferPx","640","maxBufferPx","1280",1,"viewport",3,"itemSize"],["class","row",3,"selected","click",4,"cdkVirtualFor","cdkVirtualForOf","cdkVirtualForTrackBy"],["class","empty",4,"ngIf"],[1,"row",3,"click"],[1,"lane"],[1,"dot"],["class","line",4,"ngIf"],[1,"content"],[1,"subject",3,"title"],[1,"meta"],[1,"hash"],[1,"dot-sep"],[1,"author"],[1,"date"],["class","badges",4,"ngIf"],[1,"line"],[1,"badges"],["class","badge tag",4,"ngFor","ngForOf"],["class","badge branch",4,"ngFor","ngForOf"],[1,"badge","tag"],[1,"badge","branch"],[1,"empty"]],template:function(e,t){e&1&&(l(0,"div",0)(1,"span",1),c(2),a(),l(3,"span",2)(4,"kbd",3),c(5,"j"),a(),c(6,"/"),l(7,"kbd",3),c(8,"k"),a(),c(9," navigate "),a()(),l(10,"cdk-virtual-scroll-viewport",4),v(11,hi,20,17,"button",5)(12,_i,3,0,"div",6),a()),e&2&&(s(2),Ne("",t.commits().length," of ",t.state.total()),s(8),u("itemSize",64),s(),u("cdkVirtualForOf",t.commits())("cdkVirtualForTrackBy",t.trackByHash),s(),u("ngIf",!t.commits().length&&!t.state.loading()))},dependencies:[T,U,I,yn,xn,wn,mt,Fe],styles:["[_nghost-%COMP%]{display:flex;flex-direction:column;height:100%;min-height:0;background:var(--bg-surface);border-right:1px solid var(--border-soft)}.header[_ngcontent-%COMP%]{display:flex;align-items:center;justify-content:space-between;padding:.5rem .85rem;border-bottom:1px solid var(--border-soft);font-size:12px;color:var(--fg-muted);background:var(--bg-surface)}.viewport[_ngcontent-%COMP%]{flex:1;min-height:0}.row[_ngcontent-%COMP%]{display:grid;grid-template-columns:24px 1fr auto;gap:.5rem;align-items:center;width:100%;height:64px;padding:.45rem .85rem;background:transparent;border:0;border-bottom:1px solid var(--border-soft);color:inherit;text-align:left;cursor:pointer;transition:background .1s}.row[_ngcontent-%COMP%]:hover{background:var(--bg-hover)}.row.selected[_ngcontent-%COMP%]{background:var(--bg-selected)}.row.selected[_ngcontent-%COMP%] .subject[_ngcontent-%COMP%]{color:var(--fg-primary)}.lane[_ngcontent-%COMP%]{position:relative;width:24px;height:100%;display:flex;align-items:center;justify-content:center}.dot[_ngcontent-%COMP%]{width:10px;height:10px;border-radius:50%;background:var(--accent);box-shadow:0 0 0 2px var(--bg-surface);z-index:1}.dot.merge[_ngcontent-%COMP%]{background:transparent;border:2px solid var(--accent)}.line[_ngcontent-%COMP%]{position:absolute;top:50%;left:50%;width:2px;height:50%;background:var(--border-strong);transform:translate(-50%)}.content[_ngcontent-%COMP%]{display:flex;flex-direction:column;min-width:0;gap:2px}.subject[_ngcontent-%COMP%]{font-weight:500;color:var(--fg-primary);white-space:nowrap;overflow:hidden;text-overflow:ellipsis}.meta[_ngcontent-%COMP%]{display:flex;gap:6px;font-size:11px;color:var(--fg-muted);align-items:center}.hash[_ngcontent-%COMP%]{font-family:var(--font-mono)}.dot-sep[_ngcontent-%COMP%]{opacity:.5}.badges[_ngcontent-%COMP%]{display:flex;gap:4px;flex-wrap:wrap}.badge[_ngcontent-%COMP%]{font-size:10px;font-weight:600;padding:2px 6px;border-radius:999px;letter-spacing:.02em}.badge.tag[_ngcontent-%COMP%]{background:#d9770626;color:var(--warning)}.badge.branch[_ngcontent-%COMP%]{background:var(--accent-soft);color:var(--accent)}.empty[_ngcontent-%COMP%]{padding:2rem 1rem;text-align:center;color:var(--fg-muted)}"],changeDetection:0})};var Qe=class i{http=f(ze);base="/api";list(n={}){let e=new Ut;for(let[t,o]of Object.entries(n))o&&(e=e.set(t,String(o)));return this.http.get(`${this.base}/groups`,{params:e})}static \u0275fac=function(e){return new(e||i)};static \u0275prov=V({token:i,factory:i.\u0275fac,providedIn:"root"})};function vi(i,n){if(i&1&&(l(0,"span",7),c(1),a()),i&2){let e=n.ngIf;s(),B("",e," groups")}}function Ci(i,n){i&1&&(l(0,"div",8),c(1,"Loading groups\u2026"),a())}function xi(i,n){if(i&1&&(l(0,"div",9),c(1),a()),i&2){let e=n.ngIf;s(),_(e)}}function bi(i,n){i&1&&(l(0,"div",8),c(1," No groups detected. Try the flat view. "),a())}function wi(i,n){if(i&1&&(l(0,"span",18),c(1),a()),i&2){let e=C().$implicit;s(),B("#",e.prNumber)}}function yi(i,n){if(i&1){let e=F();l(0,"li",21),S("click",function(){let o=M(e).$implicit,r=C(3);return O(r.state.selectHash(o))}),l(1,"code",22),c(2),a(),l(3,"span",23),c(4),a()()}if(i&2){let e=n.$implicit,t=C(3);z("selected",e===t.state.selectedHash()),s(2),_(t.shortHash(e)),s(2),_(t.subjectFor(e))}}function Si(i,n){if(i&1&&(l(0,"ul",19),v(1,yi,5,4,"li",20),a()),i&2){let e=C().$implicit;s(),u("ngForOf",e.commits)}}function Mi(i,n){if(i&1){let e=F();l(0,"li",10)(1,"button",11),S("click",function(){let o=M(e).$implicit,r=C();return O(r.toggle(o.id))}),l(2,"span",12),c(3,"\u25B8"),a(),l(4,"span",13),c(5),a(),v(6,wi,2,1,"span",14),l(7,"span",15),c(8),a(),l(9,"span",16),c(10),a()(),v(11,Si,2,1,"ul",17),a()}if(i&2){let e=n.$implicit,t=C();z("expanded",t.isExpanded(e.id)),s(2),z("open",t.isExpanded(e.id)),s(2),At("src-"+e.source),s(),_(t.sourceLabel(e.source)),s(),u("ngIf",e.prNumber),s(2),_(e.title),s(2),_(e.commits.length),s(),u("ngIf",t.isExpanded(e.id))}}var qe=class i{state=f(G);groupsApi=f(Qe);groups=x(null);loading=x(!1);error=x(null);expanded=x(new Set);subjectMap=ee(()=>{let n=new Map;for(let e of this.state.commits())n.set(e.hash,e.subject);return n});constructor(){j(()=>{let n=this.state.filters();this.load(n.since,n.until,n.author)})}isExpanded(n){return this.expanded().has(n)}toggle(n){let e=new Set(this.expanded());e.has(n)?e.delete(n):e.add(n),this.expanded.set(e)}shortHash(n){return n.slice(0,7)}subjectFor(n){return this.subjectMap().get(n)??n.slice(0,7)}sourceLabel(n){switch(n){case"merge":return"PR";case"squash":return"PR (sq)";case"conventional":return"Feat";case"standalone":return"commit"}}load(n,e,t){this.loading.set(!0),this.error.set(null),this.groupsApi.list({since:n,until:e,author:t}).subscribe({next:o=>{this.groups.set(o),this.loading.set(!1);let r=o.find(m=>m.prNumber);r&&this.expanded.set(new Set([r.id]))},error:o=>{this.error.set(this.errMsg(o)),this.loading.set(!1)}})}errMsg(n){if(n&&typeof n=="object"&&"error"in n){let e=n.error;if(e?.error)return e.error}return n instanceof Error?n.message:"Failed to load groups"}static \u0275fac=function(e){return new(e||i)};static \u0275cmp=D({type:i,selectors:[["app-grouped-list"]],decls:9,vars:5,consts:[[1,"head"],[1,"title"],["class","meta",4,"ngIf"],["class","empty",4,"ngIf"],["class","empty error",4,"ngIf"],[1,"groups"],["class","group",3,"expanded",4,"ngFor","ngForOf"],[1,"meta"],[1,"empty"],[1,"empty","error"],[1,"group"],[1,"group-head",3,"click"],[1,"caret"],[1,"badge"],["class","pr",4,"ngIf"],[1,"g-title"],[1,"count"],["class","commits",4,"ngIf"],[1,"pr"],[1,"commits"],["class","commit",3,"selected","click",4,"ngFor","ngForOf"],[1,"commit",3,"click"],[1,"hash"],[1,"subject"]],template:function(e,t){if(e&1&&(l(0,"div",0)(1,"span",1),c(2,"PR / feature groups"),a(),v(3,vi,2,1,"span",2),a(),v(4,Ci,2,0,"div",3)(5,xi,2,1,"div",4)(6,bi,2,0,"div",3),l(7,"ul",5),v(8,Mi,12,11,"li",6),a()),e&2){let o,r;s(3),u("ngIf",(o=t.groups())==null?null:o.length),s(),u("ngIf",t.loading()),s(),u("ngIf",t.error()),s(),u("ngIf",!t.loading()&&!t.error()&&(((r=t.groups())==null?null:r.length)??0)===0),s(2),u("ngForOf",t.groups())}},dependencies:[T,U,I],styles:["[_nghost-%COMP%]{display:flex;flex-direction:column;height:100%;overflow:hidden}.head[_ngcontent-%COMP%]{display:flex;justify-content:space-between;padding:.6rem .85rem;border-bottom:1px solid var(--border-soft);background:var(--bg-surface)}.title[_ngcontent-%COMP%]{font-weight:600;font-size:13px}.meta[_ngcontent-%COMP%]{font-size:11px;color:var(--fg-muted)}.empty[_ngcontent-%COMP%]{padding:1rem .85rem;color:var(--fg-muted);font-size:12px}.empty.error[_ngcontent-%COMP%]{color:var(--danger)}.groups[_ngcontent-%COMP%]{list-style:none;margin:0;padding:0;overflow-y:auto;flex:1}.group[_ngcontent-%COMP%]{border-bottom:1px solid var(--border-soft)}.group-head[_ngcontent-%COMP%]{width:100%;display:flex;align-items:center;gap:.5rem;padding:.55rem .85rem;background:transparent;border:0;color:var(--fg-primary);cursor:pointer;text-align:left}.group-head[_ngcontent-%COMP%]:hover{background:var(--bg-elevated)}.caret[_ngcontent-%COMP%]{display:inline-block;width:10px;transition:transform .15s ease;color:var(--fg-muted)}.caret.open[_ngcontent-%COMP%]{transform:rotate(90deg)}.badge[_ngcontent-%COMP%]{font-size:10px;letter-spacing:.04em;padding:1px 6px;border-radius:3px;background:var(--bg-elevated);color:var(--fg-secondary);text-transform:uppercase}.badge.src-merge[_ngcontent-%COMP%]{background:#6366f12e;color:var(--accent)}.badge.src-squash[_ngcontent-%COMP%]{background:#10b9812e;color:#10b981}.badge.src-conventional[_ngcontent-%COMP%]{background:#f59e0b2e;color:#d97706}.pr[_ngcontent-%COMP%]{font-size:11px;color:var(--fg-muted)}.g-title[_ngcontent-%COMP%]{flex:1;font-size:13px;white-space:nowrap;overflow:hidden;text-overflow:ellipsis}.count[_ngcontent-%COMP%]{font-size:11px;color:var(--fg-muted);background:var(--bg-elevated);padding:1px 6px;border-radius:999px}.commits[_ngcontent-%COMP%]{list-style:none;margin:0;padding:0 0 .4rem;background:var(--bg-app)}.commit[_ngcontent-%COMP%]{display:flex;gap:.6rem;align-items:center;padding:.3rem .85rem .3rem 2rem;cursor:pointer;font-size:12px}.commit[_ngcontent-%COMP%]:hover{background:var(--bg-elevated)}.commit.selected[_ngcontent-%COMP%]{background:color-mix(in oklab,var(--accent) 20%,transparent)}.commit[_ngcontent-%COMP%] .hash[_ngcontent-%COMP%]{font-family:var(--font-mono, monospace);font-size:11px;color:var(--fg-muted)}.commit[_ngcontent-%COMP%] .subject[_ngcontent-%COMP%]{flex:1;white-space:nowrap;overflow:hidden;text-overflow:ellipsis}"],changeDetection:0})};function Oi(i,n){i&1&&(Re(0),b(1,"app-grouped-list"),Ie())}function Ei(i,n){i&1&&b(0,"app-commit-list")}var Sn=class i{state=f(G);static \u0275fac=function(e){return new(e||i)};static \u0275cmp=D({type:i,selectors:[["app-home-shell"]],decls:9,vars:2,consts:[["flat",""],[1,"layout"],[1,"pane","graph"],[1,"pane","list"],[4,"ngIf","ngIfElse"],[1,"pane","detail"]],template:function(e,t){if(e&1&&(l(0,"main",1)(1,"aside",2),b(2,"app-commit-graph"),a(),l(3,"section",3),v(4,Oi,2,0,"ng-container",4)(5,Ei,1,0,"ng-template",null,0,Ve),a(),l(7,"section",5),b(8,"app-commit-detail"),a()()),e&2){let o=Te(6);s(4),u("ngIf",t.state.viewMode()==="grouped")("ngIfElse",o)}},dependencies:[T,I,Ge,Ze,Be,qe],styles:["[_nghost-%COMP%]{display:block;flex:1;min-height:0}.layout[_ngcontent-%COMP%]{height:100%;display:grid;grid-template-columns:220px 380px 1fr;min-height:0}.pane[_ngcontent-%COMP%]{min-width:0;min-height:0;overflow:hidden}.pane.graph[_ngcontent-%COMP%]{border-right:1px solid var(--border-soft)}@media (max-width: 1100px){.layout[_ngcontent-%COMP%]{grid-template-columns:320px 1fr}.pane.graph[_ngcontent-%COMP%]{display:none}}@media (max-width: 720px){.layout[_ngcontent-%COMP%]{grid-template-columns:1fr}.pane.list[_ngcontent-%COMP%]{display:none}}"],changeDetection:0})};export{Sn as HomeShellComponent};
|
|
@@ -9,8 +9,8 @@
|
|
|
9
9
|
<meta name="theme-color" content="#0b1020" media="(prefers-color-scheme: dark)">
|
|
10
10
|
<meta name="theme-color" content="#f7f8fa" media="(prefers-color-scheme: light)">
|
|
11
11
|
<link rel="icon" type="image/svg+xml" href="data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24'%3E%3Cpath fill='%234f46e5' d='M12 .5a11.5 11.5 0 1 0 11.5 11.5A11.5 11.5 0 0 0 12 .5Zm5.7 14.83a1 1 0 0 1-1.41 1.41L13 13.41V19a1 1 0 0 1-2 0v-5.59l-3.29 3.33A1 1 0 1 1 6.3 15.34l5-5.05a1 1 0 0 1 1.42 0Z'/%3E%3C/svg%3E">
|
|
12
|
-
<style>*,:before,:after{--tw-border-spacing-x:0;--tw-border-spacing-y:0;--tw-translate-x:0;--tw-translate-y:0;--tw-rotate:0;--tw-skew-x:0;--tw-skew-y:0;--tw-scale-x:1;--tw-scale-y:1;--tw-pan-x: ;--tw-pan-y: ;--tw-pinch-zoom: ;--tw-scroll-snap-strictness:proximity;--tw-gradient-from-position: ;--tw-gradient-via-position: ;--tw-gradient-to-position: ;--tw-ordinal: ;--tw-slashed-zero: ;--tw-numeric-figure: ;--tw-numeric-spacing: ;--tw-numeric-fraction: ;--tw-ring-inset: ;--tw-ring-offset-width:0px;--tw-ring-offset-color:#fff;--tw-ring-color:rgb(59 130 246 / .5);--tw-ring-offset-shadow:0 0 #0000;--tw-ring-shadow:0 0 #0000;--tw-shadow:0 0 #0000;--tw-shadow-colored:0 0 #0000;--tw-blur: ;--tw-brightness: ;--tw-contrast: ;--tw-grayscale: ;--tw-hue-rotate: ;--tw-invert: ;--tw-saturate: ;--tw-sepia: ;--tw-drop-shadow: ;--tw-backdrop-blur: ;--tw-backdrop-brightness: ;--tw-backdrop-contrast: ;--tw-backdrop-grayscale: ;--tw-backdrop-hue-rotate: ;--tw-backdrop-invert: ;--tw-backdrop-opacity: ;--tw-backdrop-saturate: ;--tw-backdrop-sepia: ;--tw-contain-size: ;--tw-contain-layout: ;--tw-contain-paint: ;--tw-contain-style: }*,:before,:after{box-sizing:border-box;border-width:0;border-style:solid;border-color:#e5e7eb}:before,:after{--tw-content:""}html{line-height:1.5;-webkit-text-size-adjust:100%;-moz-tab-size:4;tab-size:4;font-family:ui-sans-serif,system-ui,sans-serif,"Apple Color Emoji","Segoe UI Emoji",Segoe UI Symbol,"Noto Color Emoji";font-feature-settings:normal;font-variation-settings:normal;-webkit-tap-highlight-color:transparent}body{margin:0;line-height:inherit}:root{color-scheme:light;--bg-app:#f7f8fa;--bg-surface:#ffffff;--bg-surface-2:#f3f4f6;--bg-elevated:#ffffff;--bg-hover:#eef2ff;--bg-selected:#e0e7ff;--bg-overlay:rgba(15, 23, 42, .45);--fg-primary:#0f172a;--fg-secondary:#475569;--fg-muted:#64748b;--fg-subtle:#94a3b8;--fg-inverted:#ffffff;--border-soft:#e2e8f0;--border-strong:#cbd5e1;--border-focus:#6366f1;--accent:#4f46e5;--accent-hover:#4338ca;--accent-soft:#eef2ff;--accent-fg:#ffffff;--success:#16a34a;--warning:#d97706;--danger:#dc2626;--diff-add-bg:#dcfce7;--diff-add-fg:#14532d;--diff-add-gutter:#86efac;--diff-del-bg:#fee2e2;--diff-del-fg:#7f1d1d;--diff-del-gutter:#fca5a5;--diff-hunk-bg:#f1f5f9;--diff-hunk-fg:#475569;--graph-guide:rgba(148, 163, 184, .28);--graph-row-alt:rgba(15, 23, 42, .025);--graph-row-hover:rgba(79, 70, 229, .08);--graph-row-selected:rgba(79, 70, 229, .14);--graph-node-ring:#ffffff;--graph-shadow:rgba(15, 23, 42, .12);--shadow-sm:0 1px 2px rgba(15, 23, 42, .06);--shadow-md:0 4px 12px rgba(15, 23, 42, .08);--shadow-lg:0 12px 32px rgba(15, 23, 42, .12);--radius-sm:6px;--radius-md:10px;--radius-lg:14px;--font-sans:ui-sans-serif, system-ui, -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue", Arial, sans-serif;--font-mono:ui-monospace, SFMono-Regular, Menlo, Monaco, "Cascadia Mono", "Liberation Mono", "Courier New", monospace}*,*:before,*:after{box-sizing:border-box}html,body{height:100%}body{margin:0;font-family:var(--font-sans);font-size:14px;line-height:1.5;color:var(--fg-primary);background:var(--bg-app);-webkit-font-smoothing:antialiased;-moz-osx-font-smoothing:grayscale;text-rendering:optimizeLegibility}</style><link rel="stylesheet" href="styles-
|
|
12
|
+
<style>*,:before,:after{--tw-border-spacing-x:0;--tw-border-spacing-y:0;--tw-translate-x:0;--tw-translate-y:0;--tw-rotate:0;--tw-skew-x:0;--tw-skew-y:0;--tw-scale-x:1;--tw-scale-y:1;--tw-pan-x: ;--tw-pan-y: ;--tw-pinch-zoom: ;--tw-scroll-snap-strictness:proximity;--tw-gradient-from-position: ;--tw-gradient-via-position: ;--tw-gradient-to-position: ;--tw-ordinal: ;--tw-slashed-zero: ;--tw-numeric-figure: ;--tw-numeric-spacing: ;--tw-numeric-fraction: ;--tw-ring-inset: ;--tw-ring-offset-width:0px;--tw-ring-offset-color:#fff;--tw-ring-color:rgb(59 130 246 / .5);--tw-ring-offset-shadow:0 0 #0000;--tw-ring-shadow:0 0 #0000;--tw-shadow:0 0 #0000;--tw-shadow-colored:0 0 #0000;--tw-blur: ;--tw-brightness: ;--tw-contrast: ;--tw-grayscale: ;--tw-hue-rotate: ;--tw-invert: ;--tw-saturate: ;--tw-sepia: ;--tw-drop-shadow: ;--tw-backdrop-blur: ;--tw-backdrop-brightness: ;--tw-backdrop-contrast: ;--tw-backdrop-grayscale: ;--tw-backdrop-hue-rotate: ;--tw-backdrop-invert: ;--tw-backdrop-opacity: ;--tw-backdrop-saturate: ;--tw-backdrop-sepia: ;--tw-contain-size: ;--tw-contain-layout: ;--tw-contain-paint: ;--tw-contain-style: }*,:before,:after{box-sizing:border-box;border-width:0;border-style:solid;border-color:#e5e7eb}:before,:after{--tw-content:""}html{line-height:1.5;-webkit-text-size-adjust:100%;-moz-tab-size:4;tab-size:4;font-family:ui-sans-serif,system-ui,sans-serif,"Apple Color Emoji","Segoe UI Emoji",Segoe UI Symbol,"Noto Color Emoji";font-feature-settings:normal;font-variation-settings:normal;-webkit-tap-highlight-color:transparent}body{margin:0;line-height:inherit}:root{color-scheme:light;--bg-app:#f7f8fa;--bg-surface:#ffffff;--bg-surface-2:#f3f4f6;--bg-elevated:#ffffff;--bg-hover:#eef2ff;--bg-selected:#e0e7ff;--bg-overlay:rgba(15, 23, 42, .45);--fg-primary:#0f172a;--fg-secondary:#475569;--fg-muted:#64748b;--fg-subtle:#94a3b8;--fg-inverted:#ffffff;--border-soft:#e2e8f0;--border-strong:#cbd5e1;--border-focus:#6366f1;--accent:#4f46e5;--accent-hover:#4338ca;--accent-soft:#eef2ff;--accent-fg:#ffffff;--success:#16a34a;--warning:#d97706;--danger:#dc2626;--diff-add-bg:#dcfce7;--diff-add-fg:#14532d;--diff-add-gutter:#86efac;--diff-del-bg:#fee2e2;--diff-del-fg:#7f1d1d;--diff-del-gutter:#fca5a5;--diff-hunk-bg:#f1f5f9;--diff-hunk-fg:#475569;--graph-guide:rgba(148, 163, 184, .28);--graph-row-alt:rgba(15, 23, 42, .025);--graph-row-hover:rgba(79, 70, 229, .08);--graph-row-selected:rgba(79, 70, 229, .14);--graph-node-ring:#ffffff;--graph-shadow:rgba(15, 23, 42, .12);--shadow-sm:0 1px 2px rgba(15, 23, 42, .06);--shadow-md:0 4px 12px rgba(15, 23, 42, .08);--shadow-lg:0 12px 32px rgba(15, 23, 42, .12);--radius-sm:6px;--radius-md:10px;--radius-lg:14px;--font-sans:ui-sans-serif, system-ui, -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue", Arial, sans-serif;--font-mono:ui-monospace, SFMono-Regular, Menlo, Monaco, "Cascadia Mono", "Liberation Mono", "Courier New", monospace}*,*:before,*:after{box-sizing:border-box}html,body{height:100%}body{margin:0;font-family:var(--font-sans);font-size:14px;line-height:1.5;color:var(--fg-primary);background:var(--bg-app);-webkit-font-smoothing:antialiased;-moz-osx-font-smoothing:grayscale;text-rendering:optimizeLegibility}</style><link rel="stylesheet" href="styles-AH3HC64Q.css" media="print" onload="this.media='all'"><noscript><link rel="stylesheet" href="styles-AH3HC64Q.css"></noscript></head>
|
|
13
13
|
<body>
|
|
14
14
|
<app-root></app-root>
|
|
15
|
-
<link rel="modulepreload" href="chunk-36NFLS3P.js"><link rel="modulepreload" href="chunk-YSTG766K.js"><link rel="modulepreload" href="chunk-NUMLL3OZ.js"><link rel="modulepreload" href="chunk-N7UHDKJ7.js"><link rel="modulepreload" href="chunk-3FFYILBL.js"><link rel="modulepreload" href="chunk-TQE5NWMZ.js"><script src="polyfills-5CFQRCPP.js" type="module"></script><script src="main-
|
|
15
|
+
<link rel="modulepreload" href="chunk-36NFLS3P.js"><link rel="modulepreload" href="chunk-YSTG766K.js"><link rel="modulepreload" href="chunk-NUMLL3OZ.js"><link rel="modulepreload" href="chunk-N7UHDKJ7.js"><link rel="modulepreload" href="chunk-3FFYILBL.js"><link rel="modulepreload" href="chunk-TQE5NWMZ.js"><script src="polyfills-5CFQRCPP.js" type="module"></script><script src="main-6GA6B4NK.js" type="module"></script></body>
|
|
16
16
|
</html>
|