Skip to content

Commit b499f3b

Browse files
committed
style: updated stepper when user opens calibration system
1 parent 7fe5186 commit b499f3b

File tree

1 file changed

+179
-83
lines changed

1 file changed

+179
-83
lines changed

src/views/CameraConfiguration.vue

Lines changed: 179 additions & 83 deletions
Original file line numberDiff line numberDiff line change
@@ -1,62 +1,129 @@
11
<template>
2-
<div id="box" style="text-align: center;">
2+
<div id="box" style="height: 100vh; overflow: hidden;">
33
<Toolbar v-if="!fromRuxailab" />
4-
<v-container class="mt-4" style="max-height: calc(100vh - 80px); overflow: hidden;">
5-
<v-row justify="center" style="height: 100%;">
6-
<!-- Instructions Card -->
7-
<v-col cols="12" class="text-center">
8-
<v-alert type="info" outlined prominent class="mx-auto py-2"
9-
style="max-width: 600px; font-size: 0.85rem;">
10-
<div class="d-flex align-center">
11-
<v-icon medium left>mdi-information</v-icon>
12-
<div class="text-left">
13-
<strong>Camera Setup</strong>
14-
<p class="mb-0 mt-1" style="font-size: 0.8rem;">Position your face within the guide.
15-
Ensure both eyes are visible.</p>
4+
5+
<!-- Camera Selection Modal -->
6+
<v-dialog v-model="showCameraModal" max-width="500">
7+
<v-card class="blue-bg">
8+
<v-card-title class="d-flex justify-center white--text pb-4 pt-6">
9+
<v-icon color="white" left size="32">mdi-camera</v-icon>
10+
<span style="font-size: 20px;">Select Camera</span>
11+
</v-card-title>
12+
<v-card-text class="px-6 pb-2">
13+
<p class="white--text text-center mb-4" style="font-size: 14px;">
14+
If you don't see your face correctly, please select the correct camera from the list below.
15+
</p>
16+
<v-select
17+
v-model="selectedMediaDevice"
18+
:items="mediaDevices"
19+
item-text="label"
20+
item-value="deviceId"
21+
label="Available Cameras"
22+
outlined
23+
dark
24+
color="#FF425A"
25+
item-color="#FF425A"
26+
prepend-inner-icon="mdi-camera"
27+
background-color="rgba(255, 255, 255, 0.1)"
28+
></v-select>
29+
</v-card-text>
30+
<v-card-actions class="justify-center px-6 pb-6">
31+
<v-btn color="#FF425A" dark block large @click="showCameraModal = false">
32+
<v-icon left>mdi-check</v-icon>
33+
Close
34+
</v-btn>
35+
</v-card-actions>
36+
</v-card>
37+
</v-dialog>
38+
39+
<v-container fluid style="height: calc(100vh - 64px); overflow-y: auto; overflow-x: hidden;">
40+
<v-row justify="center" align="center" style="min-height: 100%;">
41+
<v-col cols="12" md="10" lg="8" xl="6">
42+
<v-stepper v-model="setupStep" elevation="0" class="mx-auto compact-stepper">
43+
<v-stepper-header>
44+
<v-stepper-step :complete="setupStep > 1" step="1" color="#FF425A">
45+
Camera Setup
46+
</v-stepper-step>
47+
<v-divider></v-divider>
48+
<v-stepper-step :complete="setupStep > 2" step="2" color="#FF425A">
49+
Preview & Calibration
50+
</v-stepper-step>
51+
</v-stepper-header>
52+
53+
<v-stepper-items>
54+
<!-- Step 1: Instructions -->
55+
<v-stepper-content step="1" class="compact-content">
56+
<v-card flat>
57+
<v-card-text class="text-center py-2">
58+
<div class="mb-2">
59+
<v-icon size="64" color="#FF425A">mdi-camera-iris</v-icon>
60+
</div>
61+
<v-alert color="#002D51" dark dense class="mb-3">
62+
<h4 class="mb-2 text-center">What will happen:</h4>
63+
<div class="text-left mx-auto" style="max-width: 400px; font-size: 13px;">
64+
<ul class="compact-list">
65+
<li>The system will request camera permission</li>
66+
<li>Your webcam image will appear with a face guide</li>
67+
<li>Position your face inside the mask overlay</li>
68+
<li>Make sure both eyes are clearly visible</li>
69+
</ul>
70+
</div>
71+
</v-alert>
72+
<v-alert color="#FF425A" dark dense class="mx-auto" style="max-width: 400px; font-size: 12px;">
73+
<strong>Important:</strong> Please allow camera access when prompted.
74+
</v-alert>
75+
</v-card-text>
76+
</v-card>
77+
<div class="text-center pb-2">
78+
<v-btn color="#FF425A" dark @click="startCameraSetup">
79+
<v-icon left>mdi-arrow-right</v-icon>
80+
Continue
81+
</v-btn>
1682
</div>
17-
</div>
18-
</v-alert>
19-
</v-col>
20-
21-
<!-- Camera Selection -->
22-
<v-col cols="12" lg="8" md="10" class="px-6 py-1">
23-
<v-select v-model="selectedMediaDevice" :items="mediaDevices" item-text="label"
24-
item-value="deviceId" label="Select Camera" outlined dense
25-
prepend-inner-icon="mdi-camera"></v-select>
26-
</v-col>
27-
28-
<!-- Blink Threshold Configuration -->
29-
<v-col v-if="!fromRuxailab" cols="12" lg="8" md="10" class="py-1">
30-
<BlinkTresholdCard />
31-
</v-col>
32-
33-
<!-- Camera Preview -->
34-
<v-col cols="12" lg="8" md="10" class="py-1">
35-
<v-card outlined class="camera-preview-card" style="height: 100%;">
36-
<v-card-title class="justify-center py-2" style="font-size: 0.95rem;">
37-
<v-icon small left>mdi-camera-iris</v-icon>
38-
Camera Preview
39-
</v-card-title>
40-
<v-card-text class="pa-2">
41-
<div v-if="isModelLoaded" class="camera-wrapper">
42-
<video id="video-tag" autoplay playsinline />
43-
<canvas id="canvas" />
44-
<v-img v-if="isCameraOn" class="mask" src="@/assets/mask_desktop.svg" />
45-
</div>
46-
<div v-else class="loading-container" style="min-height: 200px;">
47-
<v-progress-circular :size="40" :width="6" color="green"
48-
indeterminate></v-progress-circular>
49-
<h4 class="mt-2">Loading face detection model...</h4>
50-
</div>
51-
</v-card-text>
52-
<v-card-actions class="justify-center pb-2">
53-
<v-btn class="calibration-btn" large dark color="green" :disabled="!isCameraOn"
54-
@click="goToCalibRecord()">
55-
<v-icon small left>mdi-play</v-icon>
56-
Start Calibration
57-
</v-btn>
58-
</v-card-actions>
59-
</v-card>
83+
</v-stepper-content>
84+
85+
<!-- Step 2: Camera Preview -->
86+
<v-stepper-content step="2" class="compact-content">
87+
<v-card flat>
88+
<!-- Blink Threshold Configuration -->
89+
<v-card-text v-if="!fromRuxailab" class="pb-1 pt-2 text-center">
90+
<BlinkTresholdCard />
91+
</v-card-text>
92+
93+
<!-- Camera Preview -->
94+
<v-card-text class="pa-2 text-center">
95+
<div class="d-flex justify-center mb-2">
96+
<v-btn x-small outlined color="#002D51" @click="showCameraModal = true">
97+
<v-icon left x-small>mdi-help-circle</v-icon>
98+
Camera Help
99+
</v-btn>
100+
</div>
101+
<div v-if="isModelLoaded" class="camera-wrapper mx-auto" style="max-height: 400px;">
102+
<video id="video-tag" autoplay playsinline />
103+
<canvas id="canvas" />
104+
<v-img v-if="isCameraOn" class="mask" src="@/assets/mask_desktop.svg" />
105+
</div>
106+
<div v-else class="loading-container" style="min-height: 300px;">
107+
<v-progress-circular :size="50" :width="6" color="#FF425A"
108+
indeterminate></v-progress-circular>
109+
<h4 class="mt-3">Loading face detection model...</h4>
110+
</div>
111+
</v-card-text>
112+
113+
<v-card-actions class="justify-center py-2">
114+
<v-btn text @click="setupStep = 1" class="mr-2">
115+
<v-icon left>mdi-arrow-left</v-icon>
116+
Back
117+
</v-btn>
118+
<v-btn color="#FF425A" dark :disabled="!isCameraOn" @click="goToCalibRecord()">
119+
<v-icon left>mdi-play</v-icon>
120+
Start Calibration
121+
</v-btn>
122+
</v-card-actions>
123+
</v-card>
124+
</v-stepper-content>
125+
</v-stepper-items>
126+
</v-stepper>
60127
</v-col>
61128
</v-row>
62129
</v-container>
@@ -83,7 +150,9 @@ export default {
83150
video: null,
84151
fromRuxailab: false,
85152
mediaDevices: [],
86-
selectedMediaDevice: null
153+
selectedMediaDevice: null,
154+
setupStep: 1,
155+
showCameraModal: false,
87156
};
88157
},
89158
computed: {
@@ -121,10 +190,13 @@ export default {
121190
},
122191
},
123192
mounted() {
124-
this.setupCamera()
125193
this.verifyFromRuxailab()
126194
},
127195
methods: {
196+
startCameraSetup() {
197+
this.setupStep = 2;
198+
this.setupCamera();
199+
},
128200
async setupCamera() {
129201
// Load the faceLandmarksDetection model assets.
130202
const model = await faceLandmarksDetection.load(
@@ -334,52 +406,76 @@ export default {
334406
</script>
335407

336408
<style scoped>
337-
.loading-container {
338-
text-align: center;
339-
margin-top: 8rem;
409+
/* Ruxailab Color Palette */
410+
.coral-bg {
411+
background-color: #FF425A !important;
340412
}
341413
342-
.centered-canvas {
343-
left: 50%;
344-
top: 50%;
345-
transform: translate(-50%, -50%);
414+
.blue-bg {
415+
background-color: #002D51 !important;
346416
}
347417
348-
.calibration-btn {
349-
font-weight: 600;
350-
letter-spacing: 0.5px;
351-
text-transform: none;
418+
/* Compact Stepper Styles */
419+
.compact-stepper {
420+
max-height: calc(100vh - 100px);
352421
}
353422
354-
.camera-preview-card {
355-
border: 2px solid #e0e0e0;
356-
border-radius: 12px;
423+
.compact-content {
424+
padding: 8px 16px !important;
425+
}
426+
427+
.compact-list {
428+
margin: 0;
429+
padding-left: 20px;
430+
}
431+
432+
.compact-list li {
433+
margin-bottom: 4px;
434+
}
435+
436+
.v-stepper__header {
437+
box-shadow: none !important;
438+
}
439+
440+
.loading-container {
441+
display: flex;
442+
flex-direction: column;
443+
align-items: center;
444+
justify-content: center;
445+
color: #555;
357446
}
358447
359448
.camera-wrapper {
360449
position: relative;
361-
width: 500px;
362-
height: 400px;
450+
width: 100%;
451+
max-width: 500px;
452+
height: auto;
453+
aspect-ratio: 5/4;
363454
margin: 0 auto;
455+
border: 5px solid #FF425A;
456+
border-radius: 12px;
457+
overflow: hidden;
364458
}
365459
366460
#video-tag,
367461
#canvas,
368462
.mask {
369463
position: absolute;
370464
inset: 0;
371-
width: 500px;
372-
height: 400px;
465+
width: 100%;
466+
height: 100%;
373467
object-fit: cover;
374468
}
375469
470+
#video-tag {
471+
transform: scaleX(-1);
472+
}
473+
474+
#canvas {
475+
transform: scaleX(-1);
476+
}
376477
377-
.loading-container {
378-
display: flex;
379-
flex-direction: column;
380-
align-items: center;
381-
justify-content: center;
382-
min-height: 400px;
383-
color: #555;
478+
.mask {
479+
pointer-events: none;
384480
}
385481
</style>

0 commit comments

Comments
 (0)