-
-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
8 changed files
with
453 additions
and
28 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,53 @@ | ||
name: Deploy playground demo # 工作流的名称 | ||
|
||
on: # 触发条件 | ||
push: | ||
branches: | ||
- main # 当 main 分支收到推送时触发 | ||
workflow_dispatch: # 允许手动触发 | ||
|
||
permissions: # GitHub token 的权限设置 | ||
contents: read # 读取仓库内容 | ||
pages: write # 写入 GitHub Pages | ||
id-token: write # 写入身份令牌 | ||
|
||
concurrency: # 并发控制 | ||
group: pages # 同一时间只允许一个部署任务运行 | ||
cancel-in-progress: true # 如果有新的部署,取消正在进行的部署 | ||
|
||
jobs: | ||
deploy: | ||
environment: # 环境配置 | ||
name: github-pages # 环境名称 | ||
url: ${{ steps.deployment.outputs.page_url }} # 部署后的 URL | ||
|
||
runs-on: ubuntu-latest # 运行环境 | ||
|
||
steps: | ||
- uses: actions/checkout@v4 | ||
- uses: pnpm/action-setup@v4 | ||
with: | ||
run_install: false | ||
- uses: actions/setup-node@v4 | ||
with: | ||
node-version: lts/* | ||
cache: pnpm | ||
|
||
- run: pnpm playground:build | ||
|
||
# 添加缓存验证步骤 | ||
- name: Verify build | ||
run: | | ||
if [ ! -d "playground/dist" ]; then | ||
echo "Playground build failed - dist directory not found" | ||
exit 1 | ||
fi | ||
- uses: actions/configure-pages@v5 | ||
with: | ||
enablement: true | ||
- uses: actions/upload-pages-artifact@v3 | ||
with: | ||
path: playground/dist # 指定要部署的目录 | ||
- uses: actions/deploy-pages@v4 | ||
id: deployment |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,50 @@ | ||
<!DOCTYPE html> | ||
<html lang="en"> | ||
<head> | ||
<meta charset="UTF-8"> | ||
<meta name="viewport" content="width=device-width, initial-scale=1.0"> | ||
<title></title> | ||
<link rel="stylesheet" href="./style.css"> | ||
</head> | ||
<body> | ||
<!-- GitHub Corner --> | ||
<a href="https://github.com/byronogis/pausable-timers" class="github-corner" aria-label="View source on GitHub"> | ||
<svg width="80" height="80" viewBox="0 0 250 250" style="fill:var(--primary); color:#fff; position: absolute; top: 0; border: 0; right: 0;" aria-hidden="true"> | ||
<path d="M0,0 L115,115 L130,115 L142,142 L250,250 L250,0 Z"></path> | ||
<path d="M128.3,109.0 C113.8,99.7 119.0,89.6 119.0,89.6 C122.0,82.7 120.5,78.6 120.5,78.6 C119.2,72.0 123.4,76.3 123.4,76.3 C127.3,80.9 125.5,87.3 125.5,87.3 C122.9,97.6 130.6,101.9 134.4,103.2" fill="currentColor" style="transform-origin: 130px 106px;" class="octo-arm"></path> | ||
<path d="M115.0,115.0 C114.9,115.1 118.7,116.5 119.8,115.4 L133.7,101.6 C136.9,99.2 139.9,98.4 142.2,98.6 C133.8,88.0 127.5,74.4 143.8,58.0 C148.5,53.4 154.0,51.2 159.7,51.0 C160.3,49.4 163.2,43.6 171.4,40.1 C171.4,40.1 176.1,42.5 178.8,56.2 C183.1,58.6 187.2,61.8 190.9,65.4 C194.5,69.0 197.7,73.2 200.1,77.6 C213.8,80.2 216.3,84.9 216.3,84.9 C212.7,93.1 206.9,96.0 205.4,96.6 C205.1,102.4 203.0,107.8 198.3,112.5 C181.9,128.9 168.3,122.5 157.7,114.1 C157.9,116.9 156.7,120.9 152.7,124.9 L141.0,136.5 C139.8,137.7 141.6,141.9 141.8,141.8 Z" fill="currentColor" class="octo-body"></path> | ||
</svg> | ||
</a> | ||
<div class="container"> | ||
<div class="project-info"> | ||
<h1></h1> | ||
<span class="version"></span> | ||
</div> | ||
<div class="timer-display"> | ||
<div class="progress-container"> | ||
<div class="progress-bar"></div> | ||
</div> | ||
<div class="status-text"></div> | ||
</div> | ||
|
||
<div class="control-panel"> | ||
<div class="input-group"> | ||
<input type="number" id="timeInput" value="5000" min="100" step="100"> | ||
<label>ms</label> | ||
<select id="modeSelect"> | ||
<option value="timeout">Timeout</option> | ||
<option value="interval">Interval</option> | ||
</select> | ||
</div> | ||
|
||
<div class="button-group"> | ||
<button id="startBtn">Start</button> | ||
<button id="pauseBtn" disabled>Pause</button> | ||
<button id="clearBtn" disabled>Clear</button> | ||
<button id="restartBtn" disabled>Restart</button> | ||
</div> | ||
</div> | ||
</div> | ||
<script type="module" src="./main.js"></script> | ||
</body> | ||
</html> |
This file was deleted.
Oops, something went wrong.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,180 @@ | ||
import pkg from '../package.json' | ||
import { pausableTimers } from '../src/index' | ||
|
||
// 设置页面标题和项目信息 | ||
document.title = `${pkg.name} | Playground` | ||
document.querySelector('.project-info h1').textContent = pkg.name | ||
document.querySelector('.version').textContent = `v${pkg.version}` | ||
|
||
const elements = { | ||
progressBar: document.querySelector('.progress-bar'), | ||
statusText: document.querySelector('.status-text'), | ||
timeInput: document.querySelector('#timeInput'), | ||
modeSelect: document.querySelector('#modeSelect'), | ||
startBtn: document.querySelector('#startBtn'), | ||
pauseBtn: document.querySelector('#pauseBtn'), | ||
clearBtn: document.querySelector('#clearBtn'), | ||
restartBtn: document.querySelector('#restartBtn'), | ||
} | ||
|
||
let timer = null | ||
let animationFrameId = null | ||
let cycleCount = 0 | ||
|
||
function updateProgress(remaining, total) { | ||
const progress = (remaining / total) * 100 | ||
const progressBar = elements.progressBar | ||
|
||
// 完全移除过渡效果 | ||
progressBar.style.transition = 'none' | ||
progressBar.style.width = `${progress}%` | ||
|
||
if (remaining === total) { | ||
// 当需要重置到 100% 时,保持 none | ||
return | ||
} | ||
|
||
// 确保 DOM 更新后再添加过渡效果 | ||
requestAnimationFrame(() => { | ||
progressBar.style.transition = 'width 0.1s linear' | ||
}) | ||
} | ||
|
||
function updateButtons(isRunning) { | ||
elements.startBtn.disabled = isRunning | ||
elements.pauseBtn.disabled = !isRunning | ||
elements.clearBtn.disabled = !isRunning | ||
elements.restartBtn.disabled = !isRunning | ||
elements.timeInput.disabled = isRunning | ||
elements.modeSelect.disabled = isRunning | ||
} | ||
|
||
function animate(total) { | ||
if (!timer) | ||
return | ||
|
||
const remaining = timer.getRemainingTime() | ||
updateProgress(remaining, total) | ||
|
||
// 根据模式显示不同的状态信息 | ||
if (elements.modeSelect.value === 'interval') { | ||
elements.statusText.textContent = `Cycle ${cycleCount} - Remaining: ${remaining}ms` | ||
} | ||
else { | ||
elements.statusText.textContent = `Remaining: ${remaining}ms` | ||
} | ||
|
||
if (timer.isCompleted()) { | ||
elements.statusText.textContent = 'Completed!' | ||
updateButtons(false) | ||
return | ||
} | ||
|
||
animationFrameId = requestAnimationFrame(() => animate(total)) | ||
} | ||
|
||
function startTimer() { | ||
const delay = Number.parseInt(elements.timeInput.value) | ||
// 添加输入值检查 | ||
if (delay < 100) { | ||
elements.statusText.textContent = 'Please enter a value greater than 100ms' | ||
return | ||
} | ||
|
||
const mode = elements.modeSelect.value | ||
|
||
// 先清理现有的计时器和动画 | ||
if (timer) { | ||
timer.clear() | ||
} | ||
if (animationFrameId) { | ||
cancelAnimationFrame(animationFrameId) | ||
animationFrameId = null | ||
} | ||
|
||
elements.statusText.textContent = '' | ||
timer = pausableTimers(() => { | ||
if (mode === 'timeout') { | ||
cancelAnimationFrame(animationFrameId) | ||
updateProgress(0, delay) | ||
elements.statusText.textContent = 'Completed!' | ||
updateButtons(false) | ||
} | ||
else { | ||
// 在 interval 模式下,先取消动画帧 | ||
cancelAnimationFrame(animationFrameId) | ||
// 立即重置进度条到 100%(无动画) | ||
updateProgress(delay, delay) | ||
// 在 interval 模式下添加循环次数显示 | ||
cycleCount++ | ||
elements.statusText.textContent = `Cycle ${cycleCount}` | ||
// 立即开始新的倒计时(有动画) | ||
requestAnimationFrame(() => animate(delay)) | ||
} | ||
}, delay, { mode }) | ||
|
||
updateButtons(true) | ||
// 启动时也应用相同的逻辑 | ||
updateProgress(delay, delay) | ||
requestAnimationFrame(() => animate(delay)) | ||
} | ||
|
||
// Event Listeners | ||
elements.startBtn.addEventListener('click', startTimer) | ||
|
||
elements.pauseBtn.addEventListener('click', () => { | ||
if (!timer) | ||
return | ||
if (timer.isPaused()) { | ||
timer.resume() | ||
elements.pauseBtn.textContent = 'Pause' | ||
animate(Number.parseInt(elements.timeInput.value)) | ||
} | ||
else { | ||
timer.pause() | ||
elements.pauseBtn.textContent = 'Resume' | ||
cancelAnimationFrame(animationFrameId) | ||
} | ||
}) | ||
|
||
elements.clearBtn.addEventListener('click', () => { | ||
if (!timer) | ||
return | ||
timer.clear() | ||
// 确保动画帧被取消 | ||
if (animationFrameId) { | ||
cancelAnimationFrame(animationFrameId) | ||
animationFrameId = null | ||
} | ||
updateProgress(100, 100) | ||
elements.statusText.textContent = '' | ||
updateButtons(false) | ||
elements.pauseBtn.textContent = 'Pause' | ||
cycleCount = 0 | ||
}) | ||
|
||
elements.restartBtn.addEventListener('click', () => { | ||
if (!timer) | ||
return | ||
// 先清理现有的动画帧 | ||
if (animationFrameId) { | ||
cancelAnimationFrame(animationFrameId) | ||
animationFrameId = null | ||
} | ||
timer.restart() | ||
elements.pauseBtn.textContent = 'Pause' | ||
updateProgress(Number.parseInt(elements.timeInput.value), Number.parseInt(elements.timeInput.value)) | ||
animate(Number.parseInt(elements.timeInput.value)) | ||
cycleCount = 0 | ||
}) | ||
|
||
// 添加输入框验证 | ||
elements.timeInput.addEventListener('input', (e) => { | ||
const value = Number.parseInt(e.target.value) | ||
if (value < 100) { | ||
e.target.setCustomValidity('Please enter a value greater than 100ms') | ||
} | ||
else { | ||
e.target.setCustomValidity('') | ||
} | ||
}) |
Oops, something went wrong.