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

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
70 changes: 70 additions & 0 deletions .github/workflows/windows.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,70 @@
name: Windows build

on:
push:
branches: [main]
tags: ["v*"]
pull_request:
branches: [main]
workflow_dispatch:

permissions:
contents: read

jobs:
build:
runs-on: windows-2022
steps:
- name: Check out source
uses: actions/checkout@v4

- name: Configure x64 Release
run: cmake -S . -B build/release -G "Visual Studio 17 2022" -A x64

- name: Build
run: cmake --build build/release --config Release --parallel

- name: Run self-test
shell: pwsh
run: powershell.exe -NoProfile -ExecutionPolicy Bypass -File ./scripts/ci-smoke.ps1 -Exe ./build/release/bin/Release/Peek.exe

- name: Prepare artifact
shell: pwsh
run: |
New-Item -ItemType Directory -Force -Path artifact | Out-Null
Copy-Item build/release/bin/Release/Peek.exe artifact/Peek.exe
$hash = (Get-FileHash artifact/Peek.exe -Algorithm SHA256).Hash
"$hash Peek.exe" | Set-Content artifact/SHA256SUMS.txt -Encoding ascii

- name: Upload build artifact
uses: actions/upload-artifact@v4
with:
name: Peek-windows-x64
path: artifact/*
if-no-files-found: error

publish:
if: startsWith(github.ref, 'refs/tags/v')
needs: build
runs-on: windows-2022
permissions:
contents: write
steps:
- name: Download verified build
uses: actions/download-artifact@v4
with:
name: Peek-windows-x64
path: artifact

- name: Create or update GitHub Release
shell: pwsh
env:
GH_TOKEN: ${{ github.token }}
run: |
gh release view "${{ github.ref_name }}" 2>$null
if ($LASTEXITCODE -eq 0) {
gh release upload "${{ github.ref_name }}" artifact/Peek.exe artifact/SHA256SUMS.txt --clobber
} else {
gh release create "${{ github.ref_name }}" artifact/Peek.exe artifact/SHA256SUMS.txt --generate-notes --title "${{ github.ref_name }}"
}
if ($LASTEXITCODE -ne 0) { exit $LASTEXITCODE }
2 changes: 2 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,8 @@
[![License: MIT](https://img.shields.io/github/license/HaBaDEDE/Peek?style=flat-square)](LICENSE)
![Windows 10/11](https://img.shields.io/badge/Windows-10%20%7C%2011-0078D4?style=flat-square&logo=windows)

**[官方网站 / Official website](https://habadede.github.io/Peek/)**

[简体中文](#readme-zh) · [English](#readme-en)

**[下载最新版本](https://github.com/HaBaDEDE/Peek/releases/latest/download/Peek.exe) · [Download latest release](https://github.com/HaBaDEDE/Peek/releases/latest/download/Peek.exe)**
Expand Down
1 change: 1 addition & 0 deletions docs/.nojekyll
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@

140 changes: 140 additions & 0 deletions docs/index.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,140 @@
<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<meta name="theme-color" content="#0d1b2f">
<meta name="description" content="Peek is a tiny native Windows utility that identifies transient processes, file locks, and UI elements.">
<meta property="og:title" content="Peek — Three answers. One tiny Windows tool.">
<meta property="og:description" content="Ghost · Unlock · Focus. Native Win32, offline, portable, bilingual.">
<meta property="og:type" content="website">
<meta property="og:url" content="https://habadede.github.io/Peek/">
<meta property="og:image" content="https://habadede.github.io/Peek/images/social-preview.png">
<title>Peek — Tiny native Windows utility</title>
<link rel="icon" href="images/peek-icon.png">
<link rel="stylesheet" href="site.css">
<script type="application/ld+json">
{
"@context": "https://schema.org",
"@type": "SoftwareApplication",
"name": "Peek",
"applicationCategory": "UtilitiesApplication",
"operatingSystem": "Windows 10, Windows 11",
"softwareVersion": "0.1.0",
"isAccessibleForFree": true,
"license": "https://opensource.org/license/mit",
"downloadUrl": "https://github.com/HaBaDEDE/Peek/releases/latest/download/Peek.exe",
"codeRepository": "https://github.com/HaBaDEDE/Peek"
}
</script>
</head>
<body>
<header class="topbar">
<a class="brand" href="#top" aria-label="Peek home">
<img src="images/peek-icon.png" width="36" height="36" alt="">
<span>Peek</span>
</a>
<nav aria-label="Primary navigation">
<a href="#features" data-en="Features" data-zh="功能">Features</a>
<a href="#privacy" data-en="Privacy" data-zh="隐私">Privacy</a>
<a href="https://github.com/HaBaDEDE/Peek" data-en="Source" data-zh="源代码">Source</a>
<button class="language" id="language" type="button" aria-label="Switch language">中文</button>
</nav>
</header>

<main id="top">
<section class="hero">
<div class="hero-copy">
<p class="eyebrow" data-en="NATIVE WINDOWS UTILITY" data-zh="原生 WINDOWS 工具">NATIVE WINDOWS UTILITY</p>
<h1 data-en="Three answers. One tiny Windows tool." data-zh="三个问题,一个极小的 Windows 工具。">Three answers. One tiny Windows tool.</h1>
<p class="lead" data-en="Find what flashed past, who locked a file, and which Windows UI is under the pointer." data-zh="找出刚才一闪而过的程序、占用文件的进程,以及鼠标下方的 Windows 控件。">Find what flashed past, who locked a file, and which Windows UI is under the pointer.</p>
<div class="actions">
<a class="button primary" href="https://github.com/HaBaDEDE/Peek/releases/latest/download/Peek.exe" data-en="Download Peek.exe" data-zh="下载 Peek.exe">Download Peek.exe</a>
<a class="button secondary" href="https://github.com/HaBaDEDE/Peek/releases/latest" data-en="Release notes" data-zh="版本说明">Release notes</a>
</div>
<p class="requirements" data-en="Windows 10/11 · x64 · Portable · No account · No telemetry" data-zh="Windows 10/11 · x64 · 免安装 · 无账户 · 无遥测">Windows 10/11 · x64 · Portable · No account · No telemetry</p>
</div>
<div class="hero-visual">
<img src="images/peek-demo-ghost-hd.png" alt="Peek Ghost showing recent process events">
</div>
</section>

<section class="demo" aria-labelledby="demo-title">
<div>
<p class="section-label" data-en="REAL WORKFLOW" data-zh="真实使用流程">REAL WORKFLOW</p>
<h2 id="demo-title" data-en="The answer is one hotkey away." data-zh="按一次快捷键,马上得到答案。">The answer is one hotkey away.</h2>
</div>
<video controls muted loop playsinline preload="metadata" poster="images/peek-demo-ghost-hd.png">
<source src="media/peek-ghost-demo.mp4" type="video/mp4">
</video>
</section>

<section id="features" class="features" aria-labelledby="features-title">
<div class="section-heading">
<p class="section-label" data-en="THREE FOCUSED TOOLS" data-zh="三个专注功能">THREE FOCUSED TOOLS</p>
<h2 id="features-title" data-en="Only what you need, when you need it." data-zh="需要的时候,只给你需要的信息。">Only what you need, when you need it.</h2>
</div>

<article class="feature-card">
<div class="feature-copy">
<span class="number">01</span>
<h3>Ghost</h3>
<p class="question" data-en="What just flashed past?" data-zh="刚才闪过去的是什么?">What just flashed past?</p>
<p data-en="Keeps the latest short-lived process and top-level window events in memory, including lifetime, path, command line, and parent process when Windows makes them available." data-zh="在内存中保留最近的短生命周期进程与顶层窗口事件,并尽量显示存活时间、路径、命令行和父进程。">Keeps the latest short-lived process and top-level window events in memory, including lifetime, path, command line, and parent process when Windows makes them available.</p>
<kbd>Ctrl + Shift + G</kbd>
</div>
<img src="images/peek-demo-ghost-hd.png" alt="Ghost feature">
</article>

<article class="feature-card reverse">
<div class="feature-copy">
<span class="number">02</span>
<h3>Unlock</h3>
<p class="question" data-en="Who is using this file?" data-zh="谁正在占用这个文件?">Who is using this file?</p>
<p data-en="Drop a file or choose one. Peek uses Windows Restart Manager to identify likely owners and lets you reveal the executable or end the process after confirmation." data-zh="拖入或选择一个文件。Peek 使用 Windows Restart Manager 查找可能的占用进程,并可定位程序或在确认后结束进程。">Drop a file or choose one. Peek uses Windows Restart Manager to identify likely owners and lets you reveal the executable or end the process after confirmation.</p>
</div>
<img src="images/peek-demo-unlock-hd.png" alt="Unlock feature">
</article>

<article class="feature-card">
<div class="feature-copy">
<span class="number">03</span>
<h3>Focus</h3>
<p class="question" data-en="What Windows UI is under the pointer?" data-zh="鼠标下面的 Windows UI 是什么?">What Windows UI is under the pointer?</p>
<p data-en="Highlight a window or control and read its HWND, process, class, title, rectangle, and available UI Automation properties." data-zh="高亮窗口或控件,并读取 HWND、所属进程、窗口类、标题、区域及可用的 UI Automation 属性。">Highlight a window or control and read its HWND, process, class, title, rectangle, and available UI Automation properties.</p>
<kbd>Ctrl + Shift + F</kbd>
</div>
<img src="images/peek-demo-focus-hd.png" alt="Focus feature">
</article>
</section>

<section id="privacy" class="principles" aria-labelledby="privacy-title">
<div>
<p class="section-label" data-en="SMALL BY DESIGN" data-zh="从设计上保持极小">SMALL BY DESIGN</p>
<h2 id="privacy-title" data-en="Native, offline, and understandable." data-zh="原生、离线、简单明了。">Native, offline, and understandable.</h2>
</div>
<ul>
<li><strong data-en="Single EXE" data-zh="单文件 EXE">Single EXE</strong><span data-en="Run it directly. No installer or separate runtime." data-zh="直接运行,不需要安装器或额外运行库。">Run it directly. No installer or separate runtime.</span></li>
<li><strong data-en="No network" data-zh="不联网">No network</strong><span data-en="No account, cloud sync, online database, or telemetry." data-zh="没有账户、云同步、在线数据库或遥测。">No account, cloud sync, online database, or telemetry.</span></li>
<li><strong data-en="Native Win32" data-zh="原生 Win32">Native Win32</strong><span data-en="C++20 and Windows system APIs. No Electron or WebView." data-zh="使用 C++20 与 Windows 系统 API,不使用 Electron 或 WebView。">C++20 and Windows system APIs. No Electron or WebView.</span></li>
<li><strong data-en="Open source" data-zh="开放源代码">Open source</strong><span data-en="MIT licensed, with source and build instructions on GitHub." data-zh="采用 MIT 许可证,源代码与构建说明均公开在 GitHub。">MIT licensed, with source and build instructions on GitHub.</span></li>
</ul>
</section>

<section class="download">
<img src="images/peek-icon.png" width="88" height="88" alt="Peek icon">
<div>
<h2 data-en="Keep the answer one action away." data-zh="让答案始终只差一次操作。">Keep the answer one action away.</h2>
<p data-en="Download the portable Windows x64 release." data-zh="下载免安装的 Windows x64 版本。">Download the portable Windows x64 release.</p>
</div>
<a class="button primary" href="https://github.com/HaBaDEDE/Peek/releases/latest/download/Peek.exe" data-en="Download" data-zh="下载">Download</a>
</section>
</main>

<footer>
<span>Peek · MIT License</span>
<span data-en="No tracking on this site." data-zh="本网站不使用访问统计或追踪。">No tracking on this site.</span>
</footer>
<script src="site.js"></script>
</body>
</html>
Binary file added docs/media/peek-ghost-demo.mp4
Binary file not shown.
4 changes: 4 additions & 0 deletions docs/robots.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
User-agent: *
Allow: /

Sitemap: https://habadede.github.io/Peek/sitemap.xml
131 changes: 131 additions & 0 deletions docs/site.css
Original file line number Diff line number Diff line change
@@ -0,0 +1,131 @@
:root {
color-scheme: light;
--ink: #10213a;
--muted: #5e6f87;
--blue: #2869e8;
--blue-dark: #174fbd;
--line: #dce4ef;
--panel: #f5f8fc;
--navy: #0d1b2f;
}

* { box-sizing: border-box; }
html { scroll-behavior: smooth; }
body {
margin: 0;
color: var(--ink);
background: #fff;
font-family: "Segoe UI Variable Text", "Segoe UI", system-ui, sans-serif;
font-size: 17px;
line-height: 1.65;
}
a { color: inherit; }
img, video { display: block; max-width: 100%; }

.topbar {
position: sticky;
z-index: 10;
top: 0;
display: flex;
align-items: center;
justify-content: space-between;
height: 68px;
padding: 0 max(24px, calc((100vw - 1180px) / 2));
border-bottom: 1px solid rgba(220, 228, 239, .85);
background: rgba(255, 255, 255, .92);
backdrop-filter: blur(14px);
}
.brand { display: flex; align-items: center; gap: 10px; text-decoration: none; font-size: 21px; font-weight: 650; }
.brand img { border-radius: 9px; }
nav { display: flex; align-items: center; gap: 27px; }
nav a { color: #42536b; text-decoration: none; font-size: 15px; }
nav a:hover { color: var(--blue); }
.language { min-width: 62px; padding: 7px 12px; border: 1px solid var(--line); border-radius: 7px; color: var(--ink); background: #fff; font: inherit; font-size: 14px; cursor: pointer; }
.language:hover { border-color: #aab8cc; }

main { overflow: hidden; }
.hero {
display: grid;
grid-template-columns: minmax(0, .9fr) minmax(420px, 1.1fr);
gap: 74px;
align-items: center;
max-width: 1180px;
min-height: 690px;
margin: 0 auto;
padding: 80px 24px 92px;
}
.eyebrow, .section-label { margin: 0 0 14px; color: var(--blue); font-size: 13px; font-weight: 700; letter-spacing: .14em; }
h1, h2, h3 { margin-top: 0; line-height: 1.13; letter-spacing: -.025em; }
h1 { max-width: 650px; margin-bottom: 23px; font-size: clamp(48px, 5.1vw, 74px); font-weight: 690; }
.lead { max-width: 590px; margin: 0 0 34px; color: var(--muted); font-size: 21px; line-height: 1.6; }
.actions { display: flex; flex-wrap: wrap; gap: 12px; }
.button { display: inline-flex; align-items: center; justify-content: center; min-height: 48px; padding: 0 20px; border: 1px solid transparent; border-radius: 8px; text-decoration: none; font-size: 15px; font-weight: 650; }
.primary { color: #fff; background: var(--blue); box-shadow: 0 8px 24px rgba(40, 105, 232, .2); }
.primary:hover { background: var(--blue-dark); }
.secondary { border-color: var(--line); background: #fff; }
.secondary:hover { border-color: #b8c5d6; background: #f9fbfd; }
.requirements { margin: 20px 0 0; color: #708199; font-size: 13px; }
.hero-visual { position: relative; padding: 26px; border-radius: 30px; background: linear-gradient(140deg, #eaf2ff, #f7f9fc); }
.hero-visual::after { position: absolute; inset: 8% -12% auto auto; z-index: -1; width: 360px; height: 360px; border-radius: 50%; background: #d8e6ff; filter: blur(60px); content: ""; }
.hero-visual img { width: min(100%, 520px); margin: auto; border: 1px solid #cbd5e2; border-radius: 12px; box-shadow: 0 25px 70px rgba(23, 43, 74, .18); }

.demo { display: grid; grid-template-columns: .65fr 1.35fr; gap: 64px; align-items: start; max-width: 1180px; margin: 0 auto; padding: 104px 24px; border-top: 1px solid var(--line); }
.demo h2, .section-heading h2, .principles h2 { margin-bottom: 0; font-size: clamp(34px, 4vw, 50px); font-weight: 660; }
.demo video { width: 100%; border: 1px solid #cbd5e2; border-radius: 14px; background: var(--navy); box-shadow: 0 22px 60px rgba(23, 43, 74, .15); }

.features { padding: 110px 24px; background: var(--panel); }
.section-heading { max-width: 1180px; margin: 0 auto 72px; }
.feature-card { display: grid; grid-template-columns: .9fr 1.1fr; gap: 72px; align-items: center; max-width: 1080px; margin: 0 auto 110px; }
.feature-card:last-child { margin-bottom: 0; }
.feature-card.reverse .feature-copy { order: 2; }
.feature-card.reverse img { order: 1; }
.feature-copy { max-width: 470px; }
.number { display: block; margin-bottom: 22px; color: #8ca0bb; font-size: 13px; font-weight: 700; letter-spacing: .13em; }
.feature-card h3 { margin-bottom: 8px; font-size: 42px; font-weight: 680; }
.feature-card .question { margin: 0 0 19px; color: var(--blue); font-size: 21px; font-weight: 600; }
.feature-card p:not(.question) { margin: 0 0 25px; color: var(--muted); }
kbd { display: inline-block; padding: 8px 13px; border: 1px solid #cbd6e4; border-bottom-width: 2px; border-radius: 7px; background: #fff; color: #354962; font: 600 13px "Segoe UI", sans-serif; }
.feature-card img { max-height: 630px; margin: auto; border: 1px solid #cbd5e2; border-radius: 12px; box-shadow: 0 20px 50px rgba(23, 43, 74, .13); }

.principles { display: grid; grid-template-columns: .8fr 1.2fr; gap: 90px; max-width: 1180px; margin: 0 auto; padding: 116px 24px; }
.principles ul { display: grid; grid-template-columns: 1fr 1fr; gap: 1px; margin: 0; padding: 0; background: var(--line); border: 1px solid var(--line); list-style: none; }
.principles li { min-height: 170px; padding: 29px; background: #fff; }
.principles strong, .principles span { display: block; }
.principles strong { margin-bottom: 8px; font-size: 18px; }
.principles span { color: var(--muted); font-size: 15px; }

.download { display: grid; grid-template-columns: auto 1fr auto; gap: 25px; align-items: center; max-width: 1132px; margin: 0 auto 105px; padding: 38px; border-radius: 18px; color: #fff; background: var(--navy); }
.download img { border-radius: 18px; }
.download h2 { margin: 0 0 4px; font-size: 27px; }
.download p { margin: 0; color: #b9c6d8; }
.download .button { min-width: 130px; }

footer { display: flex; justify-content: space-between; max-width: 1180px; margin: 0 auto; padding: 28px 24px 40px; border-top: 1px solid var(--line); color: #74859b; font-size: 13px; }

@media (max-width: 850px) {
nav a { display: none; }
.hero, .demo, .principles { grid-template-columns: 1fr; }
.hero { gap: 52px; min-height: 0; padding-top: 64px; }
.hero-visual { max-width: 590px; }
.demo { gap: 36px; }
.feature-card { grid-template-columns: 1fr; gap: 36px; }
.feature-card.reverse .feature-copy, .feature-card.reverse img { order: initial; }
.feature-copy { max-width: 650px; }
.principles { gap: 45px; }
}

@media (max-width: 560px) {
body { font-size: 16px; }
h1 { font-size: 45px; }
.topbar { padding: 0 18px; }
.hero, .demo, .features, .principles { padding-left: 18px; padding-right: 18px; }
.principles ul { grid-template-columns: 1fr; }
.download { grid-template-columns: auto 1fr; margin: 0 18px 70px; padding: 26px; }
.download img { width: 58px; height: 58px; }
.download .button { grid-column: 1 / -1; }
footer { flex-direction: column; gap: 8px; padding-left: 18px; padding-right: 18px; }
}

@media (prefers-reduced-motion: reduce) {
html { scroll-behavior: auto; }
}
Loading
Loading