73 lines
3.7 KiB
HTML
73 lines
3.7 KiB
HTML
|
|
<style>
|
|
* { box-sizing: border-box; margin: 0; padding: 0; }
|
|
body { background: transparent; }
|
|
#app { font-family: var(--font-sans); padding: 1rem 0; }
|
|
#viewfinder { position: relative; width: 100%; aspect-ratio: 16/9; background: #000; border-radius: var(--border-radius-lg); overflow: hidden; }
|
|
video { width: 100%; height: 100%; object-fit: cover; display: block; }
|
|
#overlay { position: absolute; top: 0; left: 0; width: 100%; height: 100%; display: flex; align-items: center; justify-content: center; flex-direction: column; gap: 8px; }
|
|
#rec-badge { position: absolute; top: 12px; left: 12px; display: flex; align-items: center; gap: 6px; background: rgba(0,0,0,0.5); border-radius: 20px; padding: 4px 10px; color: #fff; font-size: 12px; font-weight: 500; display: none; }
|
|
#rec-dot { width: 8px; height: 8px; border-radius: 50%; background: #e24b4a; animation: blink 1s infinite; }
|
|
@keyframes blink { 0%,100%{opacity:1} 50%{opacity:0.2} }
|
|
#cam-label { position: absolute; bottom: 12px; left: 12px; background: rgba(0,0,0,0.5); border-radius: 20px; padding: 4px 10px; color: #fff; font-size: 12px; }
|
|
#controls { display: flex; align-items: center; gap: 10px; margin-top: 12px; flex-wrap: wrap; }
|
|
#start-btn { flex: 1; padding: 10px; border-radius: var(--border-radius-md); border: none; background: #1D9E75; color: #fff; font-size: 14px; font-weight: 500; cursor: pointer; }
|
|
#start-btn:hover { background: #0F6E56; }
|
|
#switch-btn { padding: 10px 16px; border-radius: var(--border-radius-md); border: 0.5px solid var(--color-border-secondary); background: var(--color-background-secondary); color: var(--color-text-primary); font-size: 14px; cursor: pointer; }
|
|
#switch-btn:hover { background: var(--color-background-tertiary); }
|
|
#status { font-size: 13px; color: var(--color-text-secondary); margin-top: 8px; }
|
|
#placeholder { color: #888; font-size: 14px; text-align: center; }
|
|
#placeholder-icon { font-size: 36px; margin-bottom: 8px; }
|
|
</style>
|
|
|
|
<div id="app">
|
|
<div id="viewfinder">
|
|
<video id="video" autoplay playsinline muted></video>
|
|
<div id="overlay">
|
|
<div id="placeholder">
|
|
<div id="placeholder-icon">📷</div>
|
|
<div>Tap "Start camera" to begin</div>
|
|
</div>
|
|
</div>
|
|
<div id="rec-badge"><div id="rec-dot"></div> REC</div>
|
|
<div id="cam-label" style="display:none"></div>
|
|
</div>
|
|
|
|
<div id="controls">
|
|
<button id="start-btn" onclick="startCamera()">Start camera</button>
|
|
<button id="switch-btn" onclick="switchCamera()" disabled>Switch camera</button>
|
|
</div>
|
|
<div id="status">No camera active</div>
|
|
</div>
|
|
|
|
<script>
|
|
let stream = null;
|
|
let facingMode = 'environment';
|
|
|
|
async function startCamera() {
|
|
try {
|
|
if (stream) { stream.getTracks().forEach(t => t.stop()); }
|
|
stream = await navigator.mediaDevices.getUserMedia({
|
|
video: { facingMode: facingMode, width: { ideal: 1280 }, height: { ideal: 720 } },
|
|
audio: false
|
|
});
|
|
const video = document.getElementById('video');
|
|
video.srcObject = stream;
|
|
document.getElementById('overlay').style.display = 'none';
|
|
document.getElementById('rec-badge').style.display = 'flex';
|
|
document.getElementById('cam-label').style.display = 'block';
|
|
document.getElementById('cam-label').textContent = facingMode === 'environment' ? 'Rear camera' : 'Front camera';
|
|
document.getElementById('start-btn').textContent = 'Restart';
|
|
document.getElementById('switch-btn').disabled = false;
|
|
document.getElementById('status').textContent = facingMode === 'environment' ? 'Rear camera active' : 'Front camera active';
|
|
} catch(e) {
|
|
document.getElementById('status').textContent = 'Camera error: ' + e.message;
|
|
}
|
|
}
|
|
|
|
function switchCamera() {
|
|
facingMode = facingMode === 'environment' ? 'user' : 'environment';
|
|
startCamera();
|
|
}
|
|
</script>
|